1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
7 #include <sys/eventfd.h>
9 #include <sys/personality.h>
10 #include <sys/prctl.h>
15 #if HAVE_VALGRIND_VALGRIND_H
16 #include <valgrind/valgrind.h>
19 #include "sd-daemon.h"
21 #include "alloc-util.h"
22 #include "architecture.h"
23 #include "argv-util.h"
24 #include "errno-list.h"
25 #include "errno-util.h"
27 #include "ioprio-util.h"
29 #include "namespace-util.h"
30 #include "parse-util.h"
31 #include "pidfd-util.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"
41 #include "time-util.h"
42 #include "user-util.h"
45 static void test_pid_get_comm_one(pid_t pid
) {
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
)];
56 log_info("/* %s */", __func__
);
58 xsprintf(path
, "/proc/"PID_FMT
"/comm", pid
);
60 if (stat(path
, &st
) == 0) {
61 ASSERT_OK(pid_get_comm(pid
, &a
));
62 log_info("PID"PID_FMT
" comm: '%s'", pid
, a
);
64 log_warning("%s not exist.", path
);
66 ASSERT_OK(pid_get_cmdline(pid
, 0, PROCESS_CMDLINE_COMM_FALLBACK
, &c
));
67 log_info("PID"PID_FMT
" cmdline: '%s'", pid
, c
);
69 ASSERT_OK(pid_get_cmdline(pid
, 8, 0, &d
));
70 log_info("PID"PID_FMT
" cmdline truncated to 8: '%s'", pid
, d
);
73 ASSERT_OK(pid_get_cmdline(pid
, 1, 0, &d
));
74 log_info("PID"PID_FMT
" cmdline truncated to 1: '%s'", pid
, d
);
76 r
= pid_get_ppid(pid
, &e
);
78 ASSERT_ERROR(r
, EADDRNOTAVAIL
);
82 log_info("PID"PID_FMT
" PPID: "PID_FMT
, pid
, e
);
86 ASSERT_TRUE(pid_is_kernel_thread(pid
) == 0 || pid
!= 1);
88 ASSERT_OK_OR(get_process_exe(pid
, &f
), -EACCES
);
89 log_info("PID"PID_FMT
" exe: '%s'", pid
, strna(f
));
91 ASSERT_OK_ZERO(pid_get_uid(pid
, &u
));
92 log_info("PID"PID_FMT
" UID: "UID_FMT
, pid
, u
);
94 ASSERT_OK_ZERO(get_process_gid(pid
, &g
));
95 log_info("PID"PID_FMT
" GID: "GID_FMT
, pid
, g
);
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
);
100 if (!detect_container() && pid
== 1)
101 ASSERT_ERROR(get_ctty_devnr(pid
, &h
), ENXIO
);
103 (void) getenv_for_pid(pid
, "PATH", &i
);
104 log_info("PID"PID_FMT
" $PATH: '%s'", pid
, strna(i
));
108 if (saved_argc
> 1) {
111 (void) parse_pid(saved_argv
[1], &pid
);
112 test_pid_get_comm_one(pid
);
115 test_pid_get_comm_one(1);
116 test_pid_get_comm_one(getpid());
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
;
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
));
128 r
= pid_get_cmdline(pid
, SIZE_MAX
, PROCESS_CMDLINE_COMM_FALLBACK
, &d
);
129 log_info(" %s", r
>= 0 ? d
: errno_to_name(r
));
131 r
= pid_get_cmdline(pid
, SIZE_MAX
, PROCESS_CMDLINE_QUOTE
, &e
);
132 log_info(" %s", r
>= 0 ? e
: errno_to_name(r
));
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
));
137 r
= pid_get_cmdline(pid
, SIZE_MAX
, PROCESS_CMDLINE_QUOTE_POSIX
, &g
);
138 log_info(" %s", r
>= 0 ? g
: errno_to_name(r
));
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
));
143 r
= pid_get_cmdline_strv(pid
, 0, &strv_a
);
145 ASSERT_NOT_NULL((joined
= strv_join(strv_a
, "\", \"")));
146 log_info(" \"%s\"", r
>= 0 ? joined
: errno_to_name(r
));
148 joined
= mfree(joined
);
150 r
= pid_get_cmdline_strv(pid
, PROCESS_CMDLINE_COMM_FALLBACK
, &strv_b
);
152 ASSERT_NOT_NULL((joined
= strv_join(strv_b
, "\", \"")));
153 log_info(" \"%s\"", r
>= 0 ? joined
: errno_to_name(r
));
156 TEST(pid_get_cmdline
) {
157 _cleanup_closedir_
DIR *d
= NULL
;
160 ASSERT_OK(proc_dir_open(&d
));
164 ASSERT_OK(r
= proc_dir_read(d
, &pid
));
166 if (r
== 0) /* EOF */
169 test_pid_get_cmdline_one(pid
);
173 static void test_pid_get_comm_escape_one(const char *input
, const char *output
) {
174 _cleanup_free_
char *n
= NULL
;
176 log_debug("input: <%s> — output: <%s>", input
, output
);
178 ASSERT_OK_ERRNO(prctl(PR_SET_NAME
, input
));
179 ASSERT_OK(pid_get_comm(0, &n
));
181 log_debug("got: <%s>", n
);
183 ASSERT_STREQ(n
, output
);
186 TEST(pid_get_comm_escape
) {
187 _cleanup_free_
char *saved
= NULL
;
189 ASSERT_OK(pid_get_comm(0, &saved
));
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");
202 ASSERT_OK_ERRNO(prctl(PR_SET_NAME
, saved
));
205 TEST(pid_is_unwaited
) {
209 ASSERT_OK_ERRNO(pid
);
215 ASSERT_OK_EQ_ERRNO(waitpid(pid
, &status
, 0), pid
);
216 ASSERT_OK_ZERO(pid_is_unwaited(pid
));
218 ASSERT_OK_POSITIVE(pid_is_unwaited(getpid_cached()));
219 ASSERT_FAIL(pid_is_unwaited(-1));
226 ASSERT_OK_ERRNO(pid
);
232 ASSERT_OK_EQ_ERRNO(waitpid(pid
, &status
, 0), pid
);
233 ASSERT_OK_ZERO(pid_is_alive(pid
));
235 ASSERT_OK_POSITIVE(pid_is_alive(getpid_cached()));
236 ASSERT_FAIL(pid_is_alive(-1));
240 ASSERT_NOT_NULL(personality_to_string(PER_LINUX
));
241 ASSERT_NULL(personality_to_string(PERSONALITY_INVALID
));
243 ASSERT_STREQ(personality_to_string(PER_LINUX
), architecture_to_string(native_architecture()));
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
);
249 ASSERT_STREQ(personality_to_string(PER_LINUX
), "x86-64");
250 ASSERT_STREQ(personality_to_string(PER_LINUX32
), "x86");
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
);
257 ASSERT_EQ(personality_from_string(personality_to_string(PER_LINUX32
)), (unsigned long) PER_LINUX32
);
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
;
269 if (geteuid() != 0) {
270 log_info("Skipping %s: not root", __func__
);
274 if (!have_namespaces()) {
275 log_notice("Testing without namespaces, skipping %s", __func__
);
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__
);
293 (void) wait_for_terminate(pid
, &si
);
295 ASSERT_EQ(si
.si_code
, CLD_EXITED
);
296 ASSERT_OK_ZERO(si
.si_status
);
303 r
= detach_mount_namespace();
305 log_warning_errno(r
, "detach mount namespace failed: %m");
306 if (!ERRNO_IS_PRIVILEGE(r
))
311 fd
= mkostemp(path
, O_CLOEXEC
);
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
));
323 /* Set RLIMIT_STACK to infinity to test we don't try to allocate unnecessarily large values to read
325 if (setrlimit(RLIMIT_STACK
, &RLIMIT_MAKE_CONST(RLIM_INFINITY
)) < 0)
326 log_warning("Testing without RLIMIT_STACK=infinity");
328 ASSERT_OK_ERRNO(unlink(path
));
330 ASSERT_OK_ERRNO(prctl(PR_SET_NAME
, "testa"));
332 ASSERT_ERROR(pid_get_cmdline(0, SIZE_MAX
, 0, &line
), ENOENT
);
334 ASSERT_OK(pid_get_cmdline(0, SIZE_MAX
, PROCESS_CMDLINE_COMM_FALLBACK
, &line
));
335 log_debug("'%s'", line
);
336 ASSERT_STREQ(line
, "[testa]");
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 */
344 ASSERT_OK(pid_get_cmdline(0, 0, PROCESS_CMDLINE_COMM_FALLBACK
, &line
));
345 log_debug("'%s'", line
);
346 ASSERT_STREQ(line
, "");
349 ASSERT_OK(pid_get_cmdline(0, 1, PROCESS_CMDLINE_COMM_FALLBACK
, &line
));
350 ASSERT_STREQ(line
, "…");
353 ASSERT_OK(pid_get_cmdline(0, 2, PROCESS_CMDLINE_COMM_FALLBACK
, &line
));
354 ASSERT_STREQ(line
, "[…");
357 ASSERT_OK(pid_get_cmdline(0, 3, PROCESS_CMDLINE_COMM_FALLBACK
, &line
));
358 ASSERT_STREQ(line
, "[t…");
361 ASSERT_OK(pid_get_cmdline(0, 4, PROCESS_CMDLINE_COMM_FALLBACK
, &line
));
362 ASSERT_STREQ(line
, "[te…");
365 ASSERT_OK(pid_get_cmdline(0, 5, PROCESS_CMDLINE_COMM_FALLBACK
, &line
));
366 ASSERT_STREQ(line
, "[tes…");
369 ASSERT_OK(pid_get_cmdline(0, 6, PROCESS_CMDLINE_COMM_FALLBACK
, &line
));
370 ASSERT_STREQ(line
, "[test…");
373 ASSERT_OK(pid_get_cmdline(0, 7, PROCESS_CMDLINE_COMM_FALLBACK
, &line
));
374 ASSERT_STREQ(line
, "[testa]");
377 ASSERT_OK(pid_get_cmdline(0, 8, PROCESS_CMDLINE_COMM_FALLBACK
, &line
));
378 ASSERT_STREQ(line
, "[testa]");
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
);
385 /* Test with multiple arguments that don't require quoting */
387 ASSERT_OK_EQ_ERRNO(write(fd
, "foo\0bar", 8), 8);
389 ASSERT_OK(pid_get_cmdline(0, SIZE_MAX
, 0, &line
));
390 log_debug("'%s'", line
);
391 ASSERT_STREQ(line
, "foo bar");
394 ASSERT_OK(pid_get_cmdline(0, SIZE_MAX
, PROCESS_CMDLINE_COMM_FALLBACK
, &line
));
395 ASSERT_STREQ(line
, "foo bar");
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
);
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");
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");
413 ASSERT_OK(pid_get_cmdline(0, 1, PROCESS_CMDLINE_COMM_FALLBACK
, &line
));
414 log_debug("'%s'", line
);
415 ASSERT_STREQ(line
, "…");
418 ASSERT_OK(pid_get_cmdline(0, 2, PROCESS_CMDLINE_COMM_FALLBACK
, &line
));
419 log_debug("'%s'", line
);
420 ASSERT_STREQ(line
, "f…");
423 ASSERT_OK(pid_get_cmdline(0, 3, PROCESS_CMDLINE_COMM_FALLBACK
, &line
));
424 log_debug("'%s'", line
);
425 ASSERT_STREQ(line
, "fo…");
428 ASSERT_OK(pid_get_cmdline(0, 4, PROCESS_CMDLINE_COMM_FALLBACK
, &line
));
429 log_debug("'%s'", line
);
430 ASSERT_STREQ(line
, "foo…");
433 ASSERT_OK(pid_get_cmdline(0, 5, PROCESS_CMDLINE_COMM_FALLBACK
, &line
));
434 log_debug("'%s'", line
);
435 ASSERT_STREQ(line
, "foo …");
438 ASSERT_OK(pid_get_cmdline(0, 6, PROCESS_CMDLINE_COMM_FALLBACK
, &line
));
439 log_debug("'%s'", line
);
440 ASSERT_STREQ(line
, "foo b…");
443 ASSERT_OK(pid_get_cmdline(0, 7, PROCESS_CMDLINE_COMM_FALLBACK
, &line
));
444 log_debug("'%s'", line
);
445 ASSERT_STREQ(line
, "foo ba…");
448 ASSERT_OK(pid_get_cmdline(0, 8, PROCESS_CMDLINE_COMM_FALLBACK
, &line
));
449 log_debug("'%s'", line
);
450 ASSERT_STREQ(line
, "foo bar…");
453 ASSERT_OK(pid_get_cmdline(0, 9, PROCESS_CMDLINE_COMM_FALLBACK
, &line
));
454 log_debug("'%s'", line
);
455 ASSERT_STREQ(line
, "foo bar …");
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…");
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…");
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");
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");
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");
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");
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
);
492 ASSERT_OK_ERRNO(ftruncate(fd
, 0));
493 ASSERT_OK_ERRNO(prctl(PR_SET_NAME
, "aaaa bbbb cccc"));
495 ASSERT_ERROR(pid_get_cmdline(0, SIZE_MAX
, 0, &line
), ENOENT
);
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]");
502 ASSERT_OK(pid_get_cmdline(0, 10, PROCESS_CMDLINE_COMM_FALLBACK
, &line
));
503 log_debug("'%s'", line
);
504 ASSERT_STREQ(line
, "[aaaa bbb…");
507 ASSERT_OK(pid_get_cmdline(0, 11, PROCESS_CMDLINE_COMM_FALLBACK
, &line
));
508 log_debug("'%s'", line
);
509 ASSERT_STREQ(line
, "[aaaa bbbb…");
512 ASSERT_OK(pid_get_cmdline(0, 12, PROCESS_CMDLINE_COMM_FALLBACK
, &line
));
513 log_debug("'%s'", line
);
514 ASSERT_STREQ(line
, "[aaaa bbbb …");
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
);
521 /* Test with multiple arguments that do require quoting */
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", "!``")
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
)));
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
);
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
);
544 ASSERT_OK(pid_get_cmdline_strv(0, 0, &args
));
545 ASSERT_TRUE(strv_equal(args
, EXPECT1v
));
546 args
= strv_free(args
);
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")
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
));
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
);
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
);
569 ASSERT_OK(pid_get_cmdline_strv(0, 0, &args
));
570 ASSERT_TRUE(strv_equal(args
, EXPECT2v
));
571 args
= strv_free(args
);
577 TEST(getpid_cached
) {
579 pid_t a
, b
, c
, d
, e
, f
, child
;
589 ASSERT_OK_ERRNO(child
);
610 ASSERT_OK(wait_for_terminate(child
, &si
));
611 ASSERT_EQ(si
.si_status
, 0);
612 ASSERT_EQ(si
.si_code
, CLD_EXITED
);
615 TEST(getpid_measure
) {
618 unsigned long long iterations
= slow_tests_enabled() ? 1000000 : 1000;
620 log_info("/* %s (%llu iterations) */", __func__
, iterations
);
622 t
= now(CLOCK_MONOTONIC
);
623 for (unsigned long long i
= 0; i
< iterations
; i
++)
625 q
= now(CLOCK_MONOTONIC
) - t
;
627 log_info(" glibc getpid(): %lf μs each", (double) q
/ iterations
);
629 iterations
*= 50; /* _cached() is about 50 times faster, so we need more iterations */
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
;
636 log_info("getpid_cached(): %lf μs each", (double) q
/ iterations
);
644 BLOCK_SIGNALS(SIGCHLD
);
646 r
= safe_fork("(test-child)", FORK_RESET_SIGNALS
|FORK_CLOSE_ALL_FDS
|FORK_DEATHSIG_SIGTERM
|FORK_REARRANGE_STDIO
|FORK_REOPEN_LOG
, &pid
);
651 usleep_safe(100 * USEC_PER_MSEC
);
656 ASSERT_OK(wait_for_terminate(pid
, &status
));
657 ASSERT_EQ(status
.si_code
, CLD_EXITED
);
658 ASSERT_EQ(status
.si_status
, 88);
660 _cleanup_(pidref_done
) PidRef child
= PIDREF_NULL
;
661 r
= pidref_safe_fork("(test-child)", FORK_DETACH
, &child
);
663 /* Don't freeze so this doesn't linger around forever in case something goes wrong. */
664 usleep_safe(100 * USEC_PER_SEC
);
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
));
673 if (is_reaper_process())
674 ASSERT_EQ(pid
, getpid_cached());
676 ASSERT_NE(pid
, getpid_cached());
680 ASSERT_EQ(PTR_TO_PID(NULL
), 0);
681 ASSERT_NULL(PID_TO_PTR(0));
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);
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
);
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
);
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
);
698 _cleanup_free_
char *s
= NULL
;
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);
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);
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
);
726 TEST(setpriority_closest
) {
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
);
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
742 if (!ERRNO_IS_PRIVILEGE(errno
))
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
)
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
)
763 p
= getpriority(PRIO_PROCESS
, 0);
766 /* It should always be possible to set our nice level to the current one */
767 ASSERT_OK_POSITIVE(setpriority_closest(p
));
770 q
= getpriority(PRIO_PROCESS
, 0);
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
));
779 q
= getpriority(PRIO_PROCESS
, 0);
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
));
789 q
= getpriority(PRIO_PROCESS
, 0);
795 /* These two should work, given the RLIMIT_NICE we set above */
796 ASSERT_OK_POSITIVE(setpriority_closest(-10));
798 q
= getpriority(PRIO_PROCESS
, 0);
802 ASSERT_OK_POSITIVE(setpriority_closest(-9));
804 q
= getpriority(PRIO_PROCESS
, 0);
808 /* This should succeed but should be clamped to the limit */
809 ASSERT_OK_ZERO(setpriority_closest(-11));
811 q
= getpriority(PRIO_PROCESS
, 0);
815 ASSERT_OK_POSITIVE(setpriority_closest(-8));
817 q
= getpriority(PRIO_PROCESS
, 0);
821 /* This should succeed but should be clamped to the limit */
822 ASSERT_OK_ZERO(setpriority_closest(-12));
824 q
= getpriority(PRIO_PROCESS
, 0);
837 ASSERT_ERROR(pid_get_ppid(1, NULL
), EADDRNOTAVAIL
);
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
);
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
);
849 for (pid_t pid
= 0;;) {
850 _cleanup_free_
char *c1
= NULL
, *c2
= NULL
;
853 r
= pid_get_ppid(pid
, &ppid
);
854 if (r
== -EADDRNOTAVAIL
) {
855 log_info("No further parent PID");
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
));
864 log_info("Parent of " PID_FMT
" (%s) is " PID_FMT
" (%s).", pid
, c1
, ppid
, c2
);
869 /* the same via pidref */
870 _cleanup_(pidref_done
) PidRef pidref
= PIDREF_NULL
;
871 ASSERT_OK(pidref_set_self(&pidref
));
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");
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
));
886 log_info("Parent of " PID_FMT
" (%s) is " PID_FMT
" (%s).", pidref
.pid
, c1
, parent
.pid
, c2
);
888 pidref_done(&pidref
);
889 pidref
= TAKE_PIDREF(parent
);
893 TEST(set_oom_score_adjust
) {
896 ASSERT_OK(get_oom_score_adjust(&a
));
898 r
= set_oom_score_adjust(OOM_SCORE_ADJ_MIN
);
899 if (!ERRNO_IS_PRIVILEGE(r
))
903 ASSERT_OK(get_oom_score_adjust(&b
));
904 ASSERT_EQ(b
, OOM_SCORE_ADJ_MIN
);
907 ASSERT_OK(set_oom_score_adjust(a
));
908 ASSERT_OK(get_oom_score_adjust(&b
));
912 static void* dummy_thread(void *p
) {
913 int fd
= PTR_TO_FD(p
);
916 /* let main thread know we are ready */
917 ASSERT_OK_EQ_ERRNO(write(fd
, &(const char) { 'x' }, 1), 1);
919 /* wait for the main thread to tell us to shut down */
920 ASSERT_OK_EQ_ERRNO(read(fd
, &x
, 1), 1);
924 TEST(get_process_threads
) {
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
);
932 _cleanup_close_pair_
int pfd
[2] = EBADF_PAIR
, ppfd
[2] = EBADF_PAIR
;
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
));
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);
947 ASSERT_OK_EQ_ERRNO(write(pfd
[1], &(const char) { 'x' }, 1), 1);
948 ASSERT_OK_ZERO_ERRNO(pthread_join(t
, NULL
));
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);
957 ASSERT_OK_EQ_ERRNO(write(ppfd
[1], &(const char) { 'x' }, 1), 1);
958 ASSERT_OK_ZERO_ERRNO(pthread_join(tt
, NULL
));
961 r
= get_process_threads(0);
969 TEST(is_reaper_process
) {
972 r
= safe_fork("(regular)", FORK_RESET_SIGNALS
|FORK_CLOSE_ALL_FDS
|FORK_REOPEN_LOG
|FORK_WAIT
, NULL
);
977 ASSERT_OK_ZERO(is_reaper_process());
981 r
= safe_fork("(newpid)", FORK_RESET_SIGNALS
|FORK_CLOSE_ALL_FDS
|FORK_REOPEN_LOG
|FORK_WAIT
, NULL
);
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");
993 r
= safe_fork("(newpid1)", FORK_RESET_SIGNALS
|FORK_CLOSE_ALL_FDS
|FORK_REOPEN_LOG
|FORK_WAIT
, NULL
);
996 /* grandchild, which is PID1 in a pidns */
997 ASSERT_OK_EQ(getpid_cached(), 1);
998 ASSERT_OK_POSITIVE(is_reaper_process());
1002 _exit(EXIT_SUCCESS
);
1005 r
= safe_fork("(subreaper)", FORK_RESET_SIGNALS
|FORK_CLOSE_ALL_FDS
|FORK_REOPEN_LOG
|FORK_WAIT
, NULL
);
1009 ASSERT_OK(make_reaper_process(true));
1011 ASSERT_OK_POSITIVE(is_reaper_process());
1012 _exit(EXIT_SUCCESS
);
1016 TEST(pid_get_start_time
) {
1017 _cleanup_(pidref_done
) PidRef pidref
= PIDREF_NULL
;
1019 ASSERT_OK(pidref_set_self(&pidref
));
1022 ASSERT_OK(pidref_get_start_time(&pidref
, &start_time
));
1023 log_info("our starttime: " USEC_FMT
, start_time
);
1025 _cleanup_(pidref_done_sigkill_wait
) PidRef child
= PIDREF_NULL
;
1027 ASSERT_OK_POSITIVE(pidref_safe_fork("(stub)", FORK_RESET_SIGNALS
|FORK_CLOSE_ALL_FDS
|FORK_REOPEN_LOG
|FORK_FREEZE
, &child
));
1030 ASSERT_OK(pidref_get_start_time(&child
, &start_time2
));
1032 log_info("child starttime: " USEC_FMT
, start_time2
);
1034 ASSERT_GE(start_time2
, start_time
);
1037 TEST(pidref_from_same_root_fs
) {
1040 _cleanup_(pidref_done
) PidRef pid1
= PIDREF_NULL
, self
= PIDREF_NULL
;
1042 ASSERT_OK(pidref_set_self(&self
));
1043 ASSERT_OK(pidref_set_pid(&pid1
, 1));
1045 ASSERT_OK_POSITIVE(pidref_from_same_root_fs(&self
, &self
));
1046 ASSERT_OK_POSITIVE(pidref_from_same_root_fs(&pid1
, &pid1
));
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.");
1052 log_info("PID1 and us have the same rootfs: %s", yes_no(r
));
1054 int q
= pidref_from_same_root_fs(&self
, &pid1
);
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
));
1062 _cleanup_close_
int efd
= eventfd(0, EFD_CLOEXEC
);
1063 ASSERT_OK_ERRNO(efd
);
1065 _cleanup_(pidref_done_sigkill_wait
) PidRef child2
= PIDREF_NULL
;
1066 r
= pidref_safe_fork("(child2)", FORK_RESET_SIGNALS
|FORK_REOPEN_LOG
, &child2
);
1070 ASSERT_OK_ERRNO(chroot("/usr"));
1073 ASSERT_OK_EQ_ERRNO(write(efd
, &u
, sizeof(u
)), (ssize_t
) sizeof(u
));
1078 ASSERT_OK_EQ_ERRNO(read(efd
, &u
, sizeof(u
)), (ssize_t
) sizeof(u
));
1080 ASSERT_OK_ZERO(pidref_from_same_root_fs(&self
, &child2
));
1081 ASSERT_OK_ZERO(pidref_from_same_root_fs(&child2
, &self
));
1084 TEST(pidfd_get_inode_id_self_cached
) {
1087 log_info("pid=" PID_FMT
, getpid_cached());
1090 r
= pidfd_get_inode_id_self_cached(&id
);
1091 if (ERRNO_IS_NEG_NOT_SUPPORTED(r
))
1092 log_info("pidfdid not supported");
1095 log_info("pidfdid=%" PRIu64
, id
);
1099 static int intro(void) {
1100 log_show_color(true);
1101 return EXIT_SUCCESS
;
1104 DEFINE_TEST_MAIN_WITH_INTRO(LOG_INFO
, intro
);