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

systemd / systemd / 19315930715

12 Nov 2025 11:39PM UTC coverage: 72.251% (-0.2%) from 72.412%
19315930715

push

github

bluca
mkosi: update debian commit reference to efdd7a637

* efdd7a6377 Install new file for upstream build
* 9ebdc6099e d/rules: enable 10-systemd-logind-root-ignore-inhibitors.rules.example on Ubuntu
* 1255cc7663 initramfs-tools: only skip chzdev rules if zdev_early=0
* 4675b281ee d/t/boot-and-services: skip apparmor test on armhf
* 214d6e37b2 d/t/boot-and-services: run transient unit to check syslog messages
* f4e196aa26 d/t/boot-and-services: tweak test_rsyslog regex
* dbd366a43e Install new files for upstream build
* bb7f8ef532 Install new files for upstream build
* efa7cee8a7 Install new file for upstream build
* 95aa1d1685 Install new file for upstream build
* b770f0f01b kernel-install: skip 55-initrd.install when an initrd generator is configured
* af8d1e3134 Update changelog for 258.1-2 release
* 2d0e73cd14 d/libnss-systemd.postinst: Ensure module is enabled for all four databases

306471 of 424176 relevant lines covered (72.25%)

1239443.53 hits per line

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

93.96
/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) {
42✔
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;
42✔
123
        int r;
42✔
124

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

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

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

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

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

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

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

148
        joined = mfree(joined);
42✔
149

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

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

169
                test_pid_get_cmdline_one(pid);
42✔
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
        pid_t pid;
1✔
267
        int r;
1✔
268

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

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

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

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

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

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

298
                return;
1✔
299
        }
300

301
        ASSERT_OK_ZERO(pid);
1✔
302

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

644
        BLOCK_SIGNALS(SIGCHLD);
2✔
645

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

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

653
                _exit(88);
1✔
654
        }
655

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

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

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

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

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

683
        ASSERT_EQ(PTR_TO_PID(PID_TO_PTR(1)), 1);
1✔
684
        ASSERT_EQ(PTR_TO_PID(PID_TO_PTR(2)), 2);
1✔
685
        ASSERT_EQ(PTR_TO_PID(PID_TO_PTR(-1)), -1);
1✔
686
        ASSERT_EQ(PTR_TO_PID(PID_TO_PTR(-2)), -2);
1✔
687

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

859
                ASSERT_OK(r);
1✔
860

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

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

866
                pid = ppid;
1✔
867
        }
868

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

881
                ASSERT_OK(r);
1✔
882

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1002
                _exit(EXIT_SUCCESS);
1✔
1003
        }
1004

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1099
TEST(getenv_for_pid) {
1✔
1100
        _cleanup_strv_free_ char **copy_env = NULL;
1✔
1101
        pid_t pid = getpid_cached();
1✔
1102
        int r;
1✔
1103

1104
        ASSERT_NOT_NULL(copy_env = strv_copy(environ));
1✔
1105

1106
        ASSERT_OK(r = pidref_safe_fork("(getenv_for_pid)", FORK_WAIT, NULL));
1✔
1107
        if (r == 0) {
2✔
1108
                STRV_FOREACH(e, copy_env) {
11✔
1109
                        const char *v = strchr(*e, '=');
10✔
1110
                        if (!v)
10✔
1111
                                continue;
×
1112

1113
                        _cleanup_free_ char *k = NULL;
×
1114
                        ASSERT_NOT_NULL(k = strndup(*e, v - *e));
10✔
1115

1116
                        v++;
10✔
1117

1118
                        _cleanup_free_ char *value = NULL;
10✔
1119
                        ASSERT_OK_POSITIVE(getenv_for_pid(pid, k, &value));
10✔
1120
                        ASSERT_STREQ(value, v);
10✔
1121
                }
1122

1123
                if (!strv_find_startswith(copy_env, "HOGEHOGE")) {
1✔
1124
                        char *value = POINTER_MAX;
1✔
1125
                        ASSERT_OK_ZERO(getenv_for_pid(pid, "HOGEHOGE", &value));
1✔
1126
                        ASSERT_NULL(value);
1✔
1127
                }
1128

1129
                _exit(EXIT_SUCCESS);
1✔
1130
        }
1131
}
1✔
1132

1133
static int intro(void) {
1✔
1134
        log_show_color(true);
1✔
1135
        return EXIT_SUCCESS;
1✔
1136
}
1137

1138
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