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