]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/test/test-process-util.c
4b713a3dde0af1526c568cdc5987852adabb840a
[thirdparty/systemd.git] / 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) {
46 struct stat st;
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)];
50 pid_t e;
51 uid_t u;
52 gid_t g;
53 dev_t h;
54 int r;
55
56 log_info("/* %s */", __func__);
57
58 xsprintf(path, "/proc/"PID_FMT"/comm", pid);
59
60 if (stat(path, &st) == 0) {
61 ASSERT_OK(pid_get_comm(pid, &a));
62 log_info("PID"PID_FMT" comm: '%s'", pid, a);
63 } else
64 log_warning("%s not exist.", path);
65
66 ASSERT_OK(pid_get_cmdline(pid, 0, PROCESS_CMDLINE_COMM_FALLBACK, &c));
67 log_info("PID"PID_FMT" cmdline: '%s'", pid, c);
68
69 ASSERT_OK(pid_get_cmdline(pid, 8, 0, &d));
70 log_info("PID"PID_FMT" cmdline truncated to 8: '%s'", pid, d);
71
72 free(d);
73 ASSERT_OK(pid_get_cmdline(pid, 1, 0, &d));
74 log_info("PID"PID_FMT" cmdline truncated to 1: '%s'", pid, d);
75
76 r = pid_get_ppid(pid, &e);
77 if (pid == 1)
78 ASSERT_ERROR(r, EADDRNOTAVAIL);
79 else
80 ASSERT_OK(r);
81 if (r >= 0) {
82 log_info("PID"PID_FMT" PPID: "PID_FMT, pid, e);
83 ASSERT_GT(e, 0);
84 }
85
86 ASSERT_TRUE(pid_is_kernel_thread(pid) == 0 || pid != 1);
87
88 ASSERT_OK_OR(get_process_exe(pid, &f), -EACCES);
89 log_info("PID"PID_FMT" exe: '%s'", pid, strna(f));
90
91 ASSERT_OK_ZERO(pid_get_uid(pid, &u));
92 log_info("PID"PID_FMT" UID: "UID_FMT, pid, u);
93
94 ASSERT_OK_ZERO(get_process_gid(pid, &g));
95 log_info("PID"PID_FMT" GID: "GID_FMT, pid, g);
96
97 ASSERT_OK_OR(get_process_environ(pid, &env), -EACCES);
98 log_info("PID"PID_FMT" strlen(environ): %zi", pid, env ? (ssize_t)strlen(env) : (ssize_t)-errno);
99
100 if (!detect_container() && pid == 1)
101 ASSERT_ERROR(get_ctty_devnr(pid, &h), ENXIO);
102
103 (void) getenv_for_pid(pid, "PATH", &i);
104 log_info("PID"PID_FMT" $PATH: '%s'", pid, strna(i));
105 }
106
107 TEST(pid_get_comm) {
108 if (saved_argc > 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)
115 test_pid_get_comm_one(1);
116 test_pid_get_comm_one(getpid());
117 }
118 }
119
120 static void test_pid_get_cmdline_one(pid_t pid) {
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;
123 int r;
124
125 r = pid_get_cmdline(pid, SIZE_MAX, 0, &c);
126 log_info("PID "PID_FMT": %s", pid, r >= 0 ? c : errno_to_name(r));
127
128 r = pid_get_cmdline(pid, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &d);
129 log_info(" %s", r >= 0 ? d : errno_to_name(r));
130
131 r = pid_get_cmdline(pid, SIZE_MAX, PROCESS_CMDLINE_QUOTE, &e);
132 log_info(" %s", r >= 0 ? e : errno_to_name(r));
133
134 r = pid_get_cmdline(pid, SIZE_MAX, PROCESS_CMDLINE_QUOTE | PROCESS_CMDLINE_COMM_FALLBACK, &f);
135 log_info(" %s", r >= 0 ? f : errno_to_name(r));
136
137 r = pid_get_cmdline(pid, SIZE_MAX, PROCESS_CMDLINE_QUOTE_POSIX, &g);
138 log_info(" %s", r >= 0 ? g : errno_to_name(r));
139
140 r = pid_get_cmdline(pid, SIZE_MAX, PROCESS_CMDLINE_QUOTE_POSIX | PROCESS_CMDLINE_COMM_FALLBACK, &h);
141 log_info(" %s", r >= 0 ? h : errno_to_name(r));
142
143 r = pid_get_cmdline_strv(pid, 0, &strv_a);
144 if (r >= 0)
145 ASSERT_NOT_NULL((joined = strv_join(strv_a, "\", \"")));
146 log_info(" \"%s\"", r >= 0 ? joined : errno_to_name(r));
147
148 joined = mfree(joined);
149
150 r = pid_get_cmdline_strv(pid, PROCESS_CMDLINE_COMM_FALLBACK, &strv_b);
151 if (r >= 0)
152 ASSERT_NOT_NULL((joined = strv_join(strv_b, "\", \"")));
153 log_info(" \"%s\"", r >= 0 ? joined : errno_to_name(r));
154 }
155
156 TEST(pid_get_cmdline) {
157 _cleanup_closedir_ DIR *d = NULL;
158 int r;
159
160 ASSERT_OK(proc_dir_open(&d));
161
162 for (;;) {
163 pid_t pid;
164 ASSERT_OK(r = proc_dir_read(d, &pid));
165
166 if (r == 0) /* EOF */
167 break;
168
169 test_pid_get_cmdline_one(pid);
170 }
171 }
172
173 static void test_pid_get_comm_escape_one(const char *input, const char *output) {
174 _cleanup_free_ char *n = NULL;
175
176 log_debug("input: <%s> — output: <%s>", input, output);
177
178 ASSERT_OK_ERRNO(prctl(PR_SET_NAME, input));
179 ASSERT_OK(pid_get_comm(0, &n));
180
181 log_debug("got: <%s>", n);
182
183 ASSERT_STREQ(n, output);
184 }
185
186 TEST(pid_get_comm_escape) {
187 _cleanup_free_ char *saved = NULL;
188
189 ASSERT_OK(pid_get_comm(0, &saved));
190
191 test_pid_get_comm_escape_one("", "");
192 test_pid_get_comm_escape_one("foo", "foo");
193 test_pid_get_comm_escape_one("012345678901234", "012345678901234");
194 test_pid_get_comm_escape_one("0123456789012345", "012345678901234");
195 test_pid_get_comm_escape_one("äöüß", "\\303\\244\\303\\266\\303\\274\\303\\237");
196 test_pid_get_comm_escape_one("xäöüß", "x\\303\\244\\303\\266\\303\\274\\303\\237");
197 test_pid_get_comm_escape_one("xxäöüß", "xx\\303\\244\\303\\266\\303\\274\\303\\237");
198 test_pid_get_comm_escape_one("xxxäöüß", "xxx\\303\\244\\303\\266\\303\\274\\303\\237");
199 test_pid_get_comm_escape_one("xxxxäöüß", "xxxx\\303\\244\\303\\266\\303\\274\\303\\237");
200 test_pid_get_comm_escape_one("xxxxxäöüß", "xxxxx\\303\\244\\303\\266\\303\\274\\303\\237");
201
202 ASSERT_OK_ERRNO(prctl(PR_SET_NAME, saved));
203 }
204
205 TEST(pid_is_unwaited) {
206 pid_t pid;
207
208 pid = fork();
209 ASSERT_OK_ERRNO(pid);
210 if (pid == 0) {
211 _exit(EXIT_SUCCESS);
212 } else {
213 int status;
214
215 ASSERT_OK_EQ_ERRNO(waitpid(pid, &status, 0), pid);
216 ASSERT_OK_ZERO(pid_is_unwaited(pid));
217 }
218 ASSERT_OK_POSITIVE(pid_is_unwaited(getpid_cached()));
219 ASSERT_FAIL(pid_is_unwaited(-1));
220 }
221
222 TEST(pid_is_alive) {
223 pid_t pid;
224
225 pid = fork();
226 ASSERT_OK_ERRNO(pid);
227 if (pid == 0) {
228 _exit(EXIT_SUCCESS);
229 } else {
230 int status;
231
232 ASSERT_OK_EQ_ERRNO(waitpid(pid, &status, 0), pid);
233 ASSERT_OK_ZERO(pid_is_alive(pid));
234 }
235 ASSERT_OK_POSITIVE(pid_is_alive(getpid_cached()));
236 ASSERT_FAIL(pid_is_alive(-1));
237 }
238
239 TEST(personality) {
240 ASSERT_NOT_NULL(personality_to_string(PER_LINUX));
241 ASSERT_NULL(personality_to_string(PERSONALITY_INVALID));
242
243 ASSERT_STREQ(personality_to_string(PER_LINUX), architecture_to_string(native_architecture()));
244
245 ASSERT_EQ(personality_from_string(personality_to_string(PER_LINUX)), (unsigned long) PER_LINUX);
246 ASSERT_EQ(personality_from_string(architecture_to_string(native_architecture())), (unsigned long) PER_LINUX);
247
248 #ifdef __x86_64__
249 ASSERT_STREQ(personality_to_string(PER_LINUX), "x86-64");
250 ASSERT_STREQ(personality_to_string(PER_LINUX32), "x86");
251
252 ASSERT_EQ(personality_from_string("x86-64"), (unsigned long) PER_LINUX);
253 ASSERT_EQ(personality_from_string("x86"), (unsigned long) PER_LINUX32);
254 ASSERT_EQ(personality_from_string("ia64"), PERSONALITY_INVALID);
255 ASSERT_EQ(personality_from_string(NULL), PERSONALITY_INVALID);
256
257 ASSERT_EQ(personality_from_string(personality_to_string(PER_LINUX32)), (unsigned long) PER_LINUX32);
258 #endif
259 }
260
261 TEST(pid_get_cmdline_harder) {
262 char path[] = "/tmp/test-cmdlineXXXXXX";
263 _cleanup_close_ int fd = -EBADF;
264 _cleanup_free_ char *line = NULL;
265 _cleanup_strv_free_ char **args = NULL;
266 pid_t pid;
267 int r;
268
269 if (geteuid() != 0) {
270 log_info("Skipping %s: not root", __func__);
271 return;
272 }
273
274 if (!have_namespaces()) {
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();
290 if (pid > 0) {
291 siginfo_t si;
292
293 (void) wait_for_terminate(pid, &si);
294
295 ASSERT_EQ(si.si_code, CLD_EXITED);
296 ASSERT_OK_ZERO(si.si_status);
297
298 return;
299 }
300
301 ASSERT_OK_ZERO(pid);
302
303 r = detach_mount_namespace();
304 if (r < 0) {
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);
312 ASSERT_OK_ERRNO(fd);
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) {
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)
326 log_warning("Testing without RLIMIT_STACK=infinity");
327
328 ASSERT_OK_ERRNO(unlink(path));
329
330 ASSERT_OK_ERRNO(prctl(PR_SET_NAME, "testa"));
331
332 ASSERT_ERROR(pid_get_cmdline(0, SIZE_MAX, 0, &line), ENOENT);
333
334 ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &line));
335 log_debug("'%s'", line);
336 ASSERT_STREQ(line, "[testa]");
337 line = mfree(line);
338
339 ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK | PROCESS_CMDLINE_QUOTE, &line));
340 log_debug("'%s'", line);
341 ASSERT_STREQ(line, "\"[testa]\""); /* quoting is enabled here */
342 line = mfree(line);
343
344 ASSERT_OK(pid_get_cmdline(0, 0, PROCESS_CMDLINE_COMM_FALLBACK, &line));
345 log_debug("'%s'", line);
346 ASSERT_STREQ(line, "");
347 line = mfree(line);
348
349 ASSERT_OK(pid_get_cmdline(0, 1, PROCESS_CMDLINE_COMM_FALLBACK, &line));
350 ASSERT_STREQ(line, "…");
351 line = mfree(line);
352
353 ASSERT_OK(pid_get_cmdline(0, 2, PROCESS_CMDLINE_COMM_FALLBACK, &line));
354 ASSERT_STREQ(line, "[…");
355 line = mfree(line);
356
357 ASSERT_OK(pid_get_cmdline(0, 3, PROCESS_CMDLINE_COMM_FALLBACK, &line));
358 ASSERT_STREQ(line, "[t…");
359 line = mfree(line);
360
361 ASSERT_OK(pid_get_cmdline(0, 4, PROCESS_CMDLINE_COMM_FALLBACK, &line));
362 ASSERT_STREQ(line, "[te…");
363 line = mfree(line);
364
365 ASSERT_OK(pid_get_cmdline(0, 5, PROCESS_CMDLINE_COMM_FALLBACK, &line));
366 ASSERT_STREQ(line, "[tes…");
367 line = mfree(line);
368
369 ASSERT_OK(pid_get_cmdline(0, 6, PROCESS_CMDLINE_COMM_FALLBACK, &line));
370 ASSERT_STREQ(line, "[test…");
371 line = mfree(line);
372
373 ASSERT_OK(pid_get_cmdline(0, 7, PROCESS_CMDLINE_COMM_FALLBACK, &line));
374 ASSERT_STREQ(line, "[testa]");
375 line = mfree(line);
376
377 ASSERT_OK(pid_get_cmdline(0, 8, PROCESS_CMDLINE_COMM_FALLBACK, &line));
378 ASSERT_STREQ(line, "[testa]");
379 line = mfree(line);
380
381 ASSERT_OK(pid_get_cmdline_strv(0, PROCESS_CMDLINE_COMM_FALLBACK, &args));
382 ASSERT_TRUE(strv_equal(args, STRV_MAKE("[testa]")));
383 args = strv_free(args);
384
385 /* Test with multiple arguments that don't require quoting */
386
387 ASSERT_OK_EQ_ERRNO(write(fd, "foo\0bar", 8), 8);
388
389 ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, 0, &line));
390 log_debug("'%s'", line);
391 ASSERT_STREQ(line, "foo bar");
392 line = mfree(line);
393
394 ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &line));
395 ASSERT_STREQ(line, "foo bar");
396 line = mfree(line);
397
398 ASSERT_OK(pid_get_cmdline_strv(0, PROCESS_CMDLINE_COMM_FALLBACK, &args));
399 ASSERT_TRUE(strv_equal(args, STRV_MAKE("foo", "bar")));
400 args = strv_free(args);
401
402 ASSERT_OK_EQ_ERRNO(write(fd, "quux", 4), 4);
403 ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, 0, &line));
404 log_debug("'%s'", line);
405 ASSERT_STREQ(line, "foo bar quux");
406 line = mfree(line);
407
408 ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &line));
409 log_debug("'%s'", line);
410 ASSERT_STREQ(line, "foo bar quux");
411 line = mfree(line);
412
413 ASSERT_OK(pid_get_cmdline(0, 1, PROCESS_CMDLINE_COMM_FALLBACK, &line));
414 log_debug("'%s'", line);
415 ASSERT_STREQ(line, "…");
416 line = mfree(line);
417
418 ASSERT_OK(pid_get_cmdline(0, 2, PROCESS_CMDLINE_COMM_FALLBACK, &line));
419 log_debug("'%s'", line);
420 ASSERT_STREQ(line, "f…");
421 line = mfree(line);
422
423 ASSERT_OK(pid_get_cmdline(0, 3, PROCESS_CMDLINE_COMM_FALLBACK, &line));
424 log_debug("'%s'", line);
425 ASSERT_STREQ(line, "fo…");
426 line = mfree(line);
427
428 ASSERT_OK(pid_get_cmdline(0, 4, PROCESS_CMDLINE_COMM_FALLBACK, &line));
429 log_debug("'%s'", line);
430 ASSERT_STREQ(line, "foo…");
431 line = mfree(line);
432
433 ASSERT_OK(pid_get_cmdline(0, 5, PROCESS_CMDLINE_COMM_FALLBACK, &line));
434 log_debug("'%s'", line);
435 ASSERT_STREQ(line, "foo …");
436 line = mfree(line);
437
438 ASSERT_OK(pid_get_cmdline(0, 6, PROCESS_CMDLINE_COMM_FALLBACK, &line));
439 log_debug("'%s'", line);
440 ASSERT_STREQ(line, "foo b…");
441 line = mfree(line);
442
443 ASSERT_OK(pid_get_cmdline(0, 7, PROCESS_CMDLINE_COMM_FALLBACK, &line));
444 log_debug("'%s'", line);
445 ASSERT_STREQ(line, "foo ba…");
446 line = mfree(line);
447
448 ASSERT_OK(pid_get_cmdline(0, 8, PROCESS_CMDLINE_COMM_FALLBACK, &line));
449 log_debug("'%s'", line);
450 ASSERT_STREQ(line, "foo bar…");
451 line = mfree(line);
452
453 ASSERT_OK(pid_get_cmdline(0, 9, PROCESS_CMDLINE_COMM_FALLBACK, &line));
454 log_debug("'%s'", line);
455 ASSERT_STREQ(line, "foo bar …");
456 line = mfree(line);
457
458 ASSERT_OK(pid_get_cmdline(0, 10, PROCESS_CMDLINE_COMM_FALLBACK, &line));
459 log_debug("'%s'", line);
460 ASSERT_STREQ(line, "foo bar q…");
461 line = mfree(line);
462
463 ASSERT_OK(pid_get_cmdline(0, 11, PROCESS_CMDLINE_COMM_FALLBACK, &line));
464 log_debug("'%s'", line);
465 ASSERT_STREQ(line, "foo bar qu…");
466 line = mfree(line);
467
468 ASSERT_OK(pid_get_cmdline(0, 12, PROCESS_CMDLINE_COMM_FALLBACK, &line));
469 log_debug("'%s'", line);
470 ASSERT_STREQ(line, "foo bar quux");
471 line = mfree(line);
472
473 ASSERT_OK(pid_get_cmdline(0, 13, PROCESS_CMDLINE_COMM_FALLBACK, &line));
474 log_debug("'%s'", line);
475 ASSERT_STREQ(line, "foo bar quux");
476 line = mfree(line);
477
478 ASSERT_OK(pid_get_cmdline(0, 14, PROCESS_CMDLINE_COMM_FALLBACK, &line));
479 log_debug("'%s'", line);
480 ASSERT_STREQ(line, "foo bar quux");
481 line = mfree(line);
482
483 ASSERT_OK(pid_get_cmdline(0, 1000, PROCESS_CMDLINE_COMM_FALLBACK, &line));
484 log_debug("'%s'", line);
485 ASSERT_STREQ(line, "foo bar quux");
486 line = mfree(line);
487
488 ASSERT_OK(pid_get_cmdline_strv(0, PROCESS_CMDLINE_COMM_FALLBACK, &args));
489 ASSERT_TRUE(strv_equal(args, STRV_MAKE("foo", "bar", "quux")));
490 args = strv_free(args);
491
492 ASSERT_OK_ERRNO(ftruncate(fd, 0));
493 ASSERT_OK_ERRNO(prctl(PR_SET_NAME, "aaaa bbbb cccc"));
494
495 ASSERT_ERROR(pid_get_cmdline(0, SIZE_MAX, 0, &line), ENOENT);
496
497 ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &line));
498 log_debug("'%s'", line);
499 ASSERT_STREQ(line, "[aaaa bbbb cccc]");
500 line = mfree(line);
501
502 ASSERT_OK(pid_get_cmdline(0, 10, PROCESS_CMDLINE_COMM_FALLBACK, &line));
503 log_debug("'%s'", line);
504 ASSERT_STREQ(line, "[aaaa bbb…");
505 line = mfree(line);
506
507 ASSERT_OK(pid_get_cmdline(0, 11, PROCESS_CMDLINE_COMM_FALLBACK, &line));
508 log_debug("'%s'", line);
509 ASSERT_STREQ(line, "[aaaa bbbb…");
510 line = mfree(line);
511
512 ASSERT_OK(pid_get_cmdline(0, 12, PROCESS_CMDLINE_COMM_FALLBACK, &line));
513 log_debug("'%s'", line);
514 ASSERT_STREQ(line, "[aaaa bbbb …");
515 line = mfree(line);
516
517 ASSERT_OK(pid_get_cmdline_strv(0, PROCESS_CMDLINE_COMM_FALLBACK, &args));
518 ASSERT_TRUE(strv_equal(args, STRV_MAKE("[aaaa bbbb cccc]")));
519 args = strv_free(args);
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));
529 ASSERT_OK_EQ_ERRNO(write(fd, CMDLINE1, sizeof(CMDLINE1)), (ssize_t) sizeof(CMDLINE1));
530 ASSERT_OK_ZERO_ERRNO(ftruncate(fd, sizeof(CMDLINE1)));
531
532 ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_QUOTE, &line));
533 log_debug("got: ==%s==", line);
534 log_debug("exp: ==%s==", EXPECT1);
535 ASSERT_STREQ(line, EXPECT1);
536 line = mfree(line);
537
538 ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_QUOTE_POSIX, &line));
539 log_debug("got: ==%s==", line);
540 log_debug("exp: ==%s==", EXPECT1p);
541 ASSERT_STREQ(line, EXPECT1p);
542 line = mfree(line);
543
544 ASSERT_OK(pid_get_cmdline_strv(0, 0, &args));
545 ASSERT_TRUE(strv_equal(args, EXPECT1v));
546 args = strv_free(args);
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));
554 ASSERT_OK_EQ_ERRNO(write(fd, CMDLINE2, sizeof(CMDLINE2)), (ssize_t) sizeof(CMDLINE2));
555 ASSERT_OK_ZERO_ERRNO(ftruncate(fd, sizeof CMDLINE2));
556
557 ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_QUOTE, &line));
558 log_debug("got: ==%s==", line);
559 log_debug("exp: ==%s==", EXPECT2);
560 ASSERT_STREQ(line, EXPECT2);
561 line = mfree(line);
562
563 ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_QUOTE_POSIX, &line));
564 log_debug("got: ==%s==", line);
565 log_debug("exp: ==%s==", EXPECT2p);
566 ASSERT_STREQ(line, EXPECT2p);
567 line = mfree(line);
568
569 ASSERT_OK(pid_get_cmdline_strv(0, 0, &args));
570 ASSERT_TRUE(strv_equal(args, EXPECT2v));
571 args = strv_free(args);
572
573 safe_close(fd);
574 _exit(EXIT_SUCCESS);
575 }
576
577 TEST(getpid_cached) {
578 siginfo_t si;
579 pid_t a, b, c, d, e, f, child;
580
581 a = getpid();
582 b = getpid_cached();
583 c = getpid();
584
585 ASSERT_EQ(a, b);
586 ASSERT_EQ(a, c);
587
588 child = fork();
589 ASSERT_OK_ERRNO(child);
590
591 if (child == 0) {
592 /* In child */
593 a = getpid();
594 b = getpid_cached();
595 c = getpid();
596
597 ASSERT_EQ(a, b);
598 ASSERT_EQ(a, c);
599 _exit(EXIT_SUCCESS);
600 }
601
602 d = getpid();
603 e = getpid_cached();
604 f = getpid();
605
606 ASSERT_EQ(a, d);
607 ASSERT_EQ(a, e);
608 ASSERT_EQ(a, f);
609
610 ASSERT_OK(wait_for_terminate(child, &si));
611 ASSERT_EQ(si.si_status, 0);
612 ASSERT_EQ(si.si_code, CLD_EXITED);
613 }
614
615 TEST(getpid_measure) {
616 usec_t t, q;
617
618 unsigned long long iterations = slow_tests_enabled() ? 1000000 : 1000;
619
620 log_info("/* %s (%llu iterations) */", __func__, iterations);
621
622 t = now(CLOCK_MONOTONIC);
623 for (unsigned long long i = 0; i < iterations; i++)
624 (void) getpid();
625 q = now(CLOCK_MONOTONIC) - t;
626
627 log_info(" glibc getpid(): %lf μs each", (double) q / iterations);
628
629 iterations *= 50; /* _cached() is about 50 times faster, so we need more iterations */
630
631 t = now(CLOCK_MONOTONIC);
632 for (unsigned long long i = 0; i < iterations; i++)
633 (void) getpid_cached();
634 q = now(CLOCK_MONOTONIC) - t;
635
636 log_info("getpid_cached(): %lf μs each", (double) q / iterations);
637 }
638
639 TEST(safe_fork) {
640 siginfo_t status;
641 pid_t pid;
642 int r;
643
644 BLOCK_SIGNALS(SIGCHLD);
645
646 r = safe_fork("(test-child)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_REARRANGE_STDIO|FORK_REOPEN_LOG, &pid);
647 ASSERT_OK(r);
648
649 if (r == 0) {
650 /* child */
651 usleep_safe(100 * USEC_PER_MSEC);
652
653 _exit(88);
654 }
655
656 ASSERT_OK(wait_for_terminate(pid, &status));
657 ASSERT_EQ(status.si_code, CLD_EXITED);
658 ASSERT_EQ(status.si_status, 88);
659
660 _cleanup_(pidref_done) PidRef child = PIDREF_NULL;
661 r = pidref_safe_fork("(test-child)", FORK_DETACH, &child);
662 if (r == 0) {
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);
669 ASSERT_GT(child.pid, 0);
670 ASSERT_OK(pidref_get_ppid(&child, &pid));
671 ASSERT_OK(pidref_kill(&child, SIGKILL));
672
673 if (is_reaper_process())
674 ASSERT_EQ(pid, getpid_cached());
675 else
676 ASSERT_NE(pid, getpid_cached());
677 }
678
679 TEST(pid_to_ptr) {
680 ASSERT_EQ(PTR_TO_PID(NULL), 0);
681 ASSERT_NULL(PID_TO_PTR(0));
682
683 ASSERT_EQ(PTR_TO_PID(PID_TO_PTR(1)), 1);
684 ASSERT_EQ(PTR_TO_PID(PID_TO_PTR(2)), 2);
685 ASSERT_EQ(PTR_TO_PID(PID_TO_PTR(-1)), -1);
686 ASSERT_EQ(PTR_TO_PID(PID_TO_PTR(-2)), -2);
687
688 ASSERT_EQ(PTR_TO_PID(PID_TO_PTR(INT16_MAX)), INT16_MAX);
689 ASSERT_EQ(PTR_TO_PID(PID_TO_PTR(INT16_MIN)), INT16_MIN);
690
691 ASSERT_EQ(PTR_TO_PID(PID_TO_PTR(INT32_MAX)), INT32_MAX);
692 ASSERT_EQ(PTR_TO_PID(PID_TO_PTR(INT32_MIN)), INT32_MIN);
693 }
694
695 static void test_ioprio_class_from_to_string_one(const char *val, int expected, int normalized) {
696 ASSERT_EQ(ioprio_class_from_string(val), expected);
697 if (expected >= 0) {
698 _cleanup_free_ char *s = NULL;
699 unsigned ret;
700 int combined;
701
702 ASSERT_OK_ZERO(ioprio_class_to_string_alloc(expected, &s));
703 /* We sometimes get a class number and sometimes a name back */
704 ASSERT_TRUE(streq(s, val) || safe_atou(val, &ret) == 0);
705
706 /* Make sure normalization works, i.e. NONE → BE gets normalized */
707 combined = ioprio_normalize(ioprio_prio_value(expected, 0));
708 ASSERT_EQ(ioprio_prio_class(combined), normalized);
709 ASSERT_TRUE(expected != IOPRIO_CLASS_NONE || ioprio_prio_data(combined) == 4);
710 }
711 }
712
713 TEST(ioprio_class_from_to_string) {
714 test_ioprio_class_from_to_string_one("none", IOPRIO_CLASS_NONE, IOPRIO_CLASS_BE);
715 test_ioprio_class_from_to_string_one("realtime", IOPRIO_CLASS_RT, IOPRIO_CLASS_RT);
716 test_ioprio_class_from_to_string_one("best-effort", IOPRIO_CLASS_BE, IOPRIO_CLASS_BE);
717 test_ioprio_class_from_to_string_one("idle", IOPRIO_CLASS_IDLE, IOPRIO_CLASS_IDLE);
718 test_ioprio_class_from_to_string_one("0", IOPRIO_CLASS_NONE, IOPRIO_CLASS_BE);
719 test_ioprio_class_from_to_string_one("1", 1, 1);
720 test_ioprio_class_from_to_string_one("7", 7, 7);
721 test_ioprio_class_from_to_string_one("8", -EINVAL, -EINVAL);
722 test_ioprio_class_from_to_string_one("9", -EINVAL, -EINVAL);
723 test_ioprio_class_from_to_string_one("-1", -EINVAL, -EINVAL);
724 }
725
726 TEST(setpriority_closest) {
727 int r;
728
729 r = safe_fork("(test-setprio)",
730 FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_WAIT|FORK_LOG|FORK_REOPEN_LOG, NULL);
731 ASSERT_OK(r);
732
733 if (r == 0) {
734 bool full_test;
735 int p, q;
736 /* child */
737
738 /* rlimit of 30 equals nice level of -10 */
739 if (setrlimit(RLIMIT_NICE, &RLIMIT_MAKE_CONST(30)) < 0) {
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) {
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) {
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;
763 p = getpriority(PRIO_PROCESS, 0);
764 ASSERT_EQ(errno, 0);
765
766 /* It should always be possible to set our nice level to the current one */
767 ASSERT_OK_POSITIVE(setpriority_closest(p));
768
769 errno = 0;
770 q = getpriority(PRIO_PROCESS, 0);
771 ASSERT_EQ(errno, 0);
772 ASSERT_EQ(p, q);
773
774 /* It should also be possible to set the nice level to one higher */
775 if (p < PRIO_MAX-1) {
776 ASSERT_OK_POSITIVE(setpriority_closest(++p));
777
778 errno = 0;
779 q = getpriority(PRIO_PROCESS, 0);
780 ASSERT_EQ(errno, 0);
781 ASSERT_EQ(p, q);
782 }
783
784 /* It should also be possible to set the nice level to two higher */
785 if (p < PRIO_MAX-1) {
786 ASSERT_OK_POSITIVE(setpriority_closest(++p));
787
788 errno = 0;
789 q = getpriority(PRIO_PROCESS, 0);
790 ASSERT_EQ(errno, 0);
791 ASSERT_EQ(p, q);
792 }
793
794 if (full_test) {
795 /* These two should work, given the RLIMIT_NICE we set above */
796 ASSERT_OK_POSITIVE(setpriority_closest(-10));
797 errno = 0;
798 q = getpriority(PRIO_PROCESS, 0);
799 ASSERT_EQ(errno, 0);
800 ASSERT_EQ(q, -10);
801
802 ASSERT_OK_POSITIVE(setpriority_closest(-9));
803 errno = 0;
804 q = getpriority(PRIO_PROCESS, 0);
805 ASSERT_EQ(errno, 0);
806 ASSERT_EQ(q, -9);
807
808 /* This should succeed but should be clamped to the limit */
809 ASSERT_OK_ZERO(setpriority_closest(-11));
810 errno = 0;
811 q = getpriority(PRIO_PROCESS, 0);
812 ASSERT_EQ(errno, 0);
813 ASSERT_EQ(q, -10);
814
815 ASSERT_OK_POSITIVE(setpriority_closest(-8));
816 errno = 0;
817 q = getpriority(PRIO_PROCESS, 0);
818 ASSERT_EQ(errno, 0);
819 ASSERT_EQ(q, -8);
820
821 /* This should succeed but should be clamped to the limit */
822 ASSERT_OK_ZERO(setpriority_closest(-12));
823 errno = 0;
824 q = getpriority(PRIO_PROCESS, 0);
825 ASSERT_EQ(errno, 0);
826 ASSERT_EQ(q, -10);
827 }
828
829 _exit(EXIT_SUCCESS);
830 }
831 }
832
833 TEST(pid_get_ppid) {
834 uint64_t limit;
835 int r;
836
837 ASSERT_ERROR(pid_get_ppid(1, NULL), EADDRNOTAVAIL);
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));
841 log_debug("kernel.pid_max = %"PRIu64, limit);
842
843 if (limit < INT_MAX) {
844 r = pid_get_ppid(limit + 1, NULL);
845 log_debug_errno(r, "get_process_limit(%"PRIu64") → %d/%m", limit + 1, r);
846 assert(r == -ESRCH);
847 }
848
849 for (pid_t pid = 0;;) {
850 _cleanup_free_ char *c1 = NULL, *c2 = NULL;
851 pid_t ppid;
852
853 r = pid_get_ppid(pid, &ppid);
854 if (r == -EADDRNOTAVAIL) {
855 log_info("No further parent PID");
856 break;
857 }
858
859 ASSERT_OK(r);
860
861 ASSERT_OK(pid_get_cmdline(pid, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &c1));
862 ASSERT_OK(pid_get_cmdline(ppid, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &c2));
863
864 log_info("Parent of " PID_FMT " (%s) is " PID_FMT " (%s).", pid, c1, ppid, c2);
865
866 pid = ppid;
867 }
868
869 /* the same via pidref */
870 _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
871 ASSERT_OK(pidref_set_self(&pidref));
872 for (;;) {
873 _cleanup_free_ char *c1 = NULL, *c2 = NULL;
874 _cleanup_(pidref_done) PidRef parent = PIDREF_NULL;
875 r = pidref_get_ppid_as_pidref(&pidref, &parent);
876 if (r == -EADDRNOTAVAIL) {
877 log_info("No further parent PID");
878 break;
879 }
880
881 ASSERT_OK(r);
882
883 ASSERT_OK(pidref_get_cmdline(&pidref, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &c1));
884 ASSERT_OK(pidref_get_cmdline(&parent, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &c2));
885
886 log_info("Parent of " PID_FMT " (%s) is " PID_FMT " (%s).", pidref.pid, c1, parent.pid, c2);
887
888 pidref_done(&pidref);
889 pidref = TAKE_PIDREF(parent);
890 }
891 }
892
893 TEST(set_oom_score_adjust) {
894 int a, b, r;
895
896 ASSERT_OK(get_oom_score_adjust(&a));
897
898 r = set_oom_score_adjust(OOM_SCORE_ADJ_MIN);
899 if (!ERRNO_IS_PRIVILEGE(r))
900 ASSERT_OK(r);
901
902 if (r >= 0) {
903 ASSERT_OK(get_oom_score_adjust(&b));
904 ASSERT_EQ(b, OOM_SCORE_ADJ_MIN);
905 }
906
907 ASSERT_OK(set_oom_score_adjust(a));
908 ASSERT_OK(get_oom_score_adjust(&b));
909 ASSERT_EQ(b, a);
910 }
911
912 static void* dummy_thread(void *p) {
913 int fd = PTR_TO_FD(p);
914 char x;
915
916 /* let main thread know we are ready */
917 ASSERT_OK_EQ_ERRNO(write(fd, &(const char) { 'x' }, 1), 1);
918
919 /* wait for the main thread to tell us to shut down */
920 ASSERT_OK_EQ_ERRNO(read(fd, &x, 1), 1);
921 return NULL;
922 }
923
924 TEST(get_process_threads) {
925 int r;
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);
929 ASSERT_OK(r);
930
931 if (r == 0) {
932 _cleanup_close_pair_ int pfd[2] = EBADF_PAIR, ppfd[2] = EBADF_PAIR;
933 pthread_t t, tt;
934 char x;
935
936 ASSERT_OK_ERRNO(socketpair(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0, pfd));
937 ASSERT_OK_ERRNO(socketpair(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0, ppfd));
938
939 ASSERT_OK_EQ(get_process_threads(0), 1);
940 ASSERT_OK_ZERO_ERRNO(pthread_create(&t, NULL, &dummy_thread, FD_TO_PTR(pfd[0])));
941 ASSERT_OK_EQ_ERRNO(read(pfd[1], &x, 1), 1);
942 ASSERT_OK_EQ(get_process_threads(0), 2);
943 ASSERT_OK_ZERO_ERRNO(pthread_create(&tt, NULL, &dummy_thread, FD_TO_PTR(ppfd[0])));
944 ASSERT_OK_EQ_ERRNO(read(ppfd[1], &x, 1), 1);
945 ASSERT_OK_EQ(get_process_threads(0), 3);
946
947 ASSERT_OK_EQ_ERRNO(write(pfd[1], &(const char) { 'x' }, 1), 1);
948 ASSERT_OK_ZERO_ERRNO(pthread_join(t, NULL));
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);
954 ASSERT_OK(r);
955 ASSERT_GE(r, 2);
956
957 ASSERT_OK_EQ_ERRNO(write(ppfd[1], &(const char) { 'x' }, 1), 1);
958 ASSERT_OK_ZERO_ERRNO(pthread_join(tt, NULL));
959
960 /* similar here */
961 r = get_process_threads(0);
962 ASSERT_OK(r);
963 ASSERT_GE(r, 1);
964
965 _exit(EXIT_SUCCESS);
966 }
967 }
968
969 TEST(is_reaper_process) {
970 int r;
971
972 r = safe_fork("(regular)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_REOPEN_LOG|FORK_WAIT, NULL);
973 ASSERT_OK(r);
974 if (r == 0) {
975 /* child */
976
977 ASSERT_OK_ZERO(is_reaper_process());
978 _exit(EXIT_SUCCESS);
979 }
980
981 r = safe_fork("(newpid)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_REOPEN_LOG|FORK_WAIT, NULL);
982 ASSERT_OK(r);
983 if (r == 0) {
984 /* child */
985
986 if (unshare(CLONE_NEWPID) < 0) {
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);
994 ASSERT_OK(r);
995 if (r == 0) {
996 /* grandchild, which is PID1 in a pidns */
997 ASSERT_OK_EQ(getpid_cached(), 1);
998 ASSERT_OK_POSITIVE(is_reaper_process());
999 _exit(EXIT_SUCCESS);
1000 }
1001
1002 _exit(EXIT_SUCCESS);
1003 }
1004
1005 r = safe_fork("(subreaper)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_REOPEN_LOG|FORK_WAIT, NULL);
1006 ASSERT_OK(r);
1007 if (r == 0) {
1008 /* child */
1009 ASSERT_OK(make_reaper_process(true));
1010
1011 ASSERT_OK_POSITIVE(is_reaper_process());
1012 _exit(EXIT_SUCCESS);
1013 }
1014 }
1015
1016 TEST(pid_get_start_time) {
1017 _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
1018
1019 ASSERT_OK(pidref_set_self(&pidref));
1020
1021 usec_t start_time;
1022 ASSERT_OK(pidref_get_start_time(&pidref, &start_time));
1023 log_info("our starttime: " USEC_FMT, start_time);
1024
1025 _cleanup_(pidref_done_sigkill_wait) PidRef child = PIDREF_NULL;
1026
1027 ASSERT_OK_POSITIVE(pidref_safe_fork("(stub)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_REOPEN_LOG|FORK_FREEZE, &child));
1028
1029 usec_t start_time2;
1030 ASSERT_OK(pidref_get_start_time(&child, &start_time2));
1031
1032 log_info("child starttime: " USEC_FMT, start_time2);
1033
1034 ASSERT_GE(start_time2, start_time);
1035 }
1036
1037 TEST(pidref_from_same_root_fs) {
1038 int r;
1039
1040 _cleanup_(pidref_done) PidRef pid1 = PIDREF_NULL, self = PIDREF_NULL;
1041
1042 ASSERT_OK(pidref_set_self(&self));
1043 ASSERT_OK(pidref_set_pid(&pid1, 1));
1044
1045 ASSERT_OK_POSITIVE(pidref_from_same_root_fs(&self, &self));
1046 ASSERT_OK_POSITIVE(pidref_from_same_root_fs(&pid1, &pid1));
1047
1048 r = pidref_from_same_root_fs(&pid1, &self);
1049 if (ERRNO_IS_NEG_PRIVILEGE(r))
1050 return (void) log_tests_skipped("skipping pidref_from_same_root_fs() test, lacking privileged.");
1051 ASSERT_OK(r);
1052 log_info("PID1 and us have the same rootfs: %s", yes_no(r));
1053
1054 int q = pidref_from_same_root_fs(&self, &pid1);
1055 ASSERT_OK(q);
1056 ASSERT_EQ(r, q);
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));
1060 ASSERT_OK_POSITIVE(pidref_from_same_root_fs(&self, &child1));
1061
1062 _cleanup_close_ int efd = eventfd(0, EFD_CLOEXEC);
1063 ASSERT_OK_ERRNO(efd);
1064
1065 _cleanup_(pidref_done_sigkill_wait) PidRef child2 = PIDREF_NULL;
1066 r = pidref_safe_fork("(child2)", FORK_RESET_SIGNALS|FORK_REOPEN_LOG, &child2);
1067 ASSERT_OK(r);
1068
1069 if (r == 0) {
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;
1078 ASSERT_OK_EQ_ERRNO(read(efd, &u, sizeof(u)), (ssize_t) sizeof(u));
1079
1080 ASSERT_OK_ZERO(pidref_from_same_root_fs(&self, &child2));
1081 ASSERT_OK_ZERO(pidref_from_same_root_fs(&child2, &self));
1082 }
1083
1084 TEST(pidfd_get_inode_id_self_cached) {
1085 int r;
1086
1087 log_info("pid=" PID_FMT, getpid_cached());
1088
1089 uint64_t id;
1090 r = pidfd_get_inode_id_self_cached(&id);
1091 if (ERRNO_IS_NEG_NOT_SUPPORTED(r))
1092 log_info("pidfdid not supported");
1093 else {
1094 assert(r >= 0);
1095 log_info("pidfdid=%" PRIu64, id);
1096 }
1097 }
1098
1099 static int intro(void) {
1100 log_show_color(true);
1101 return EXIT_SUCCESS;
1102 }
1103
1104 DEFINE_TEST_MAIN_WITH_INTRO(LOG_INFO, intro);