]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/test/test-process-util.c
Fixes for vscode/intellisense parsing (#38040)
[thirdparty/systemd.git] / src / test / test-process-util.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
0b452006 2
f5947a5e 3#include <fcntl.h>
bb2d1d8e 4#include <linux/oom.h>
6aa90884 5#include <pthread.h>
fa34123c 6#include <stdlib.h>
d6267b9b 7#include <sys/eventfd.h>
69281c49 8#include <sys/mount.h>
26fbedd7 9#include <sys/personality.h>
69281c49 10#include <sys/prctl.h>
0b452006
RC
11#include <sys/stat.h>
12#include <sys/wait.h>
13#include <unistd.h>
fa34123c 14#include "strv.h"
349cc4a5 15#if HAVE_VALGRIND_VALGRIND_H
b3d69149
EV
16#include <valgrind/valgrind.h>
17#endif
0b452006 18
fa34123c
DDM
19#include "sd-daemon.h"
20
b5efdb8a 21#include "alloc-util.h"
26fbedd7 22#include "architecture.h"
fa34123c 23#include "argv-util.h"
0c4d1e6d
LP
24#include "errno-list.h"
25#include "errno-util.h"
69281c49 26#include "fd-util.h"
032b3afb 27#include "ioprio-util.h"
0b452006 28#include "log.h"
f5947a5e 29#include "missing_sched.h"
88851988 30#include "namespace-util.h"
18dade5a 31#include "parse-util.h"
afede53a 32#include "pidfd-util.h"
fa34123c 33#include "pidref.h"
07630cea 34#include "process-util.h"
0c4d1e6d 35#include "procfs-util.h"
75997c3f 36#include "rlimit-util.h"
4c253ed1 37#include "signal-util.h"
9a140c35 38#include "stdio-util.h"
07630cea 39#include "string-util.h"
288a74cc 40#include "terminal-util.h"
6d7c4033 41#include "tests.h"
fa34123c 42#include "time-util.h"
75997c3f 43#include "user-util.h"
07630cea 44#include "virt.h"
0b452006 45
d7d74854 46static void test_pid_get_comm_one(pid_t pid) {
0b452006 47 struct stat st;
ba19c6e1 48 _cleanup_free_ char *a = NULL, *c = NULL, *d = NULL, *f = NULL, *i = NULL;
0b452006 49 _cleanup_free_ char *env = NULL;
fbd0b64f 50 char path[STRLEN("/proc//comm") + DECIMAL_STR_MAX(pid_t)];
0b452006
RC
51 pid_t e;
52 uid_t u;
53 gid_t g;
54 dev_t h;
55 int r;
0b452006 56
daceaabe
ZJS
57 log_info("/* %s */", __func__);
58
9a140c35
ZJS
59 xsprintf(path, "/proc/"PID_FMT"/comm", pid);
60
61 if (stat(path, &st) == 0) {
39782096 62 ASSERT_OK(pid_get_comm(pid, &a));
9a140c35 63 log_info("PID"PID_FMT" comm: '%s'", pid, a);
cfeaa44a 64 } else
9a140c35 65 log_warning("%s not exist.", path);
0b452006 66
39782096 67 ASSERT_OK(pid_get_cmdline(pid, 0, PROCESS_CMDLINE_COMM_FALLBACK, &c));
9a140c35 68 log_info("PID"PID_FMT" cmdline: '%s'", pid, c);
0b452006 69
39782096 70 ASSERT_OK(pid_get_cmdline(pid, 8, 0, &d));
69281c49
LP
71 log_info("PID"PID_FMT" cmdline truncated to 8: '%s'", pid, d);
72
73 free(d);
39782096 74 ASSERT_OK(pid_get_cmdline(pid, 1, 0, &d));
69281c49 75 log_info("PID"PID_FMT" cmdline truncated to 1: '%s'", pid, d);
0b452006 76
47f64104 77 r = pid_get_ppid(pid, &e);
39782096
DDM
78 if (pid == 1)
79 ASSERT_ERROR(r, EADDRNOTAVAIL);
80 else
81 ASSERT_OK(r);
0c4d1e6d
LP
82 if (r >= 0) {
83 log_info("PID"PID_FMT" PPID: "PID_FMT, pid, e);
39782096 84 ASSERT_GT(e, 0);
0c4d1e6d 85 }
0b452006 86
39782096 87 ASSERT_TRUE(pid_is_kernel_thread(pid) == 0 || pid != 1);
0b452006 88
ea64d550 89 ASSERT_OK_OR(get_process_exe(pid, &f), -EACCES);
9a140c35 90 log_info("PID"PID_FMT" exe: '%s'", pid, strna(f));
0b452006 91
39782096 92 ASSERT_OK_ZERO(pid_get_uid(pid, &u));
9a140c35 93 log_info("PID"PID_FMT" UID: "UID_FMT, pid, u);
0b452006 94
39782096 95 ASSERT_OK_ZERO(get_process_gid(pid, &g));
9a140c35 96 log_info("PID"PID_FMT" GID: "GID_FMT, pid, g);
0b452006 97
ea64d550 98 ASSERT_OK_OR(get_process_environ(pid, &env), -EACCES);
9a140c35 99 log_info("PID"PID_FMT" strlen(environ): %zi", pid, env ? (ssize_t)strlen(env) : (ssize_t)-errno);
0b452006 100
39782096
DDM
101 if (!detect_container() && pid == 1)
102 ASSERT_ERROR(get_ctty_devnr(pid, &h), ENXIO);
0b452006 103
6fb05b07 104 (void) getenv_for_pid(pid, "PATH", &i);
9a140c35 105 log_info("PID"PID_FMT" $PATH: '%s'", pid, strna(i));
0b452006
RC
106}
107
d7d74854 108TEST(pid_get_comm) {
c462e63e
JJ
109 if (saved_argc > 1) {
110 pid_t pid = 0;
111
112 (void) parse_pid(saved_argv[1], &pid);
d7d74854 113 test_pid_get_comm_one(pid);
c462e63e 114 } else {
cfc9d3be
DDM
115 if (sd_booted() > 0)
116 test_pid_get_comm_one(1);
d7d74854 117 test_pid_get_comm_one(getpid());
c462e63e
JJ
118 }
119}
120
a034620f 121static void test_pid_get_cmdline_one(pid_t pid) {
201423d8
YW
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;
510c7a95
ZJS
124 int r;
125
a034620f 126 r = pid_get_cmdline(pid, SIZE_MAX, 0, &c);
510c7a95
ZJS
127 log_info("PID "PID_FMT": %s", pid, r >= 0 ? c : errno_to_name(r));
128
a034620f 129 r = pid_get_cmdline(pid, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &d);
510c7a95
ZJS
130 log_info(" %s", r >= 0 ? d : errno_to_name(r));
131
a034620f 132 r = pid_get_cmdline(pid, SIZE_MAX, PROCESS_CMDLINE_QUOTE, &e);
510c7a95
ZJS
133 log_info(" %s", r >= 0 ? e : errno_to_name(r));
134
a034620f 135 r = pid_get_cmdline(pid, SIZE_MAX, PROCESS_CMDLINE_QUOTE | PROCESS_CMDLINE_COMM_FALLBACK, &f);
510c7a95
ZJS
136 log_info(" %s", r >= 0 ? f : errno_to_name(r));
137
a034620f 138 r = pid_get_cmdline(pid, SIZE_MAX, PROCESS_CMDLINE_QUOTE_POSIX, &g);
510c7a95
ZJS
139 log_info(" %s", r >= 0 ? g : errno_to_name(r));
140
a034620f 141 r = pid_get_cmdline(pid, SIZE_MAX, PROCESS_CMDLINE_QUOTE_POSIX | PROCESS_CMDLINE_COMM_FALLBACK, &h);
510c7a95 142 log_info(" %s", r >= 0 ? h : errno_to_name(r));
201423d8 143
a034620f 144 r = pid_get_cmdline_strv(pid, 0, &strv_a);
201423d8 145 if (r >= 0)
278e3adf 146 ASSERT_NOT_NULL((joined = strv_join(strv_a, "\", \"")));
201423d8
YW
147 log_info(" \"%s\"", r >= 0 ? joined : errno_to_name(r));
148
149 joined = mfree(joined);
150
a034620f 151 r = pid_get_cmdline_strv(pid, PROCESS_CMDLINE_COMM_FALLBACK, &strv_b);
201423d8 152 if (r >= 0)
278e3adf 153 ASSERT_NOT_NULL((joined = strv_join(strv_b, "\", \"")));
201423d8 154 log_info(" \"%s\"", r >= 0 ? joined : errno_to_name(r));
510c7a95
ZJS
155}
156
a034620f 157TEST(pid_get_cmdline) {
510c7a95 158 _cleanup_closedir_ DIR *d = NULL;
957f84e9 159 int r;
510c7a95 160
39782096 161 ASSERT_OK(proc_dir_open(&d));
510c7a95 162
957f84e9 163 for (;;) {
510c7a95 164 pid_t pid;
ea64d550 165 ASSERT_OK(r = proc_dir_read(d, &pid));
510c7a95 166
957f84e9
LP
167 if (r == 0) /* EOF */
168 break;
510c7a95 169
a034620f 170 test_pid_get_cmdline_one(pid);
510c7a95
ZJS
171 }
172}
173
d7d74854 174static void test_pid_get_comm_escape_one(const char *input, const char *output) {
ce268825
LP
175 _cleanup_free_ char *n = NULL;
176
daceaabe 177 log_debug("input: <%s> — output: <%s>", input, output);
ce268825 178
39782096
DDM
179 ASSERT_OK_ERRNO(prctl(PR_SET_NAME, input));
180 ASSERT_OK(pid_get_comm(0, &n));
ce268825 181
daceaabe 182 log_debug("got: <%s>", n);
ce268825 183
c79e88b3 184 ASSERT_STREQ(n, output);
ce268825
LP
185}
186
d7d74854 187TEST(pid_get_comm_escape) {
ce268825
LP
188 _cleanup_free_ char *saved = NULL;
189
39782096 190 ASSERT_OK(pid_get_comm(0, &saved));
d7d74854
LP
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");
ce268825 202
39782096 203 ASSERT_OK_ERRNO(prctl(PR_SET_NAME, saved));
ce268825
LP
204}
205
c462e63e 206TEST(pid_is_unwaited) {
0b452006
RC
207 pid_t pid;
208
209 pid = fork();
39782096 210 ASSERT_OK_ERRNO(pid);
0b452006
RC
211 if (pid == 0) {
212 _exit(EXIT_SUCCESS);
213 } else {
214 int status;
215
39782096
DDM
216 ASSERT_OK_EQ_ERRNO(waitpid(pid, &status, 0), pid);
217 ASSERT_OK_ZERO(pid_is_unwaited(pid));
0b452006 218 }
39782096
DDM
219 ASSERT_OK_POSITIVE(pid_is_unwaited(getpid_cached()));
220 ASSERT_FAIL(pid_is_unwaited(-1));
0b452006
RC
221}
222
c462e63e 223TEST(pid_is_alive) {
0b452006
RC
224 pid_t pid;
225
226 pid = fork();
39782096 227 ASSERT_OK_ERRNO(pid);
0b452006
RC
228 if (pid == 0) {
229 _exit(EXIT_SUCCESS);
230 } else {
231 int status;
232
39782096
DDM
233 ASSERT_OK_EQ_ERRNO(waitpid(pid, &status, 0), pid);
234 ASSERT_OK_ZERO(pid_is_alive(pid));
0b452006 235 }
39782096
DDM
236 ASSERT_OK_POSITIVE(pid_is_alive(getpid_cached()));
237 ASSERT_FAIL(pid_is_alive(-1));
0b452006
RC
238}
239
c462e63e 240TEST(personality) {
39782096
DDM
241 ASSERT_NOT_NULL(personality_to_string(PER_LINUX));
242 ASSERT_NULL(personality_to_string(PERSONALITY_INVALID));
26fbedd7 243
c79e88b3 244 ASSERT_STREQ(personality_to_string(PER_LINUX), architecture_to_string(native_architecture()));
26fbedd7 245
39782096
DDM
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);
26fbedd7
LP
248
249#ifdef __x86_64__
c79e88b3
IK
250 ASSERT_STREQ(personality_to_string(PER_LINUX), "x86-64");
251 ASSERT_STREQ(personality_to_string(PER_LINUX32), "x86");
26fbedd7 252
39782096
DDM
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);
26fbedd7 257
39782096 258 ASSERT_EQ(personality_from_string(personality_to_string(PER_LINUX32)), (unsigned long) PER_LINUX32);
26fbedd7
LP
259#endif
260}
261
a034620f 262TEST(pid_get_cmdline_harder) {
69281c49 263 char path[] = "/tmp/test-cmdlineXXXXXX";
254d1313 264 _cleanup_close_ int fd = -EBADF;
69281c49 265 _cleanup_free_ char *line = NULL;
201423d8 266 _cleanup_strv_free_ char **args = NULL;
69281c49 267 pid_t pid;
88851988 268 int r;
69281c49 269
92f6a1b6
YW
270 if (geteuid() != 0) {
271 log_info("Skipping %s: not root", __func__);
69281c49 272 return;
92f6a1b6 273 }
69281c49 274
5f00dc4d
LP
275 if (!have_namespaces()) {
276 log_notice("Testing without namespaces, skipping %s", __func__);
277 return;
278 }
279
349cc4a5 280#if HAVE_VALGRIND_VALGRIND_H
b3d69149 281 /* valgrind patches open(/proc//cmdline)
a034620f 282 * so, test_pid_get_cmdline_harder fails always
b3d69149 283 * See https://github.com/systemd/systemd/pull/3555#issuecomment-226564908 */
92f6a1b6
YW
284 if (RUNNING_ON_VALGRIND) {
285 log_info("Skipping %s: running on valgrind", __func__);
b3d69149 286 return;
92f6a1b6 287 }
b3d69149
EV
288#endif
289
69281c49
LP
290 pid = fork();
291 if (pid > 0) {
292 siginfo_t si;
293
294 (void) wait_for_terminate(pid, &si);
295
39782096
DDM
296 ASSERT_EQ(si.si_code, CLD_EXITED);
297 ASSERT_OK_ZERO(si.si_status);
69281c49
LP
298
299 return;
300 }
301
39782096 302 ASSERT_OK_ZERO(pid);
69281c49 303
88851988
LP
304 r = detach_mount_namespace();
305 if (r < 0) {
306 log_warning_errno(r, "detach mount namespace failed: %m");
39782096
DDM
307 if (!ERRNO_IS_PRIVILEGE(r))
308 ASSERT_OK(r);
0ffa4c7c
EV
309 return;
310 }
c58fd466 311
69281c49 312 fd = mkostemp(path, O_CLOEXEC);
39782096 313 ASSERT_OK_ERRNO(fd);
347ebd02 314
0ffa4c7c
EV
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. */
347ebd02
ZJS
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");
39782096 320 ASSERT_TRUE(IN_SET(errno, EPERM, EACCES));
347ebd02
ZJS
321 return;
322 }
323
905a56d5 324 /* Set RLIMIT_STACK to infinity to test we don't try to allocate unnecessarily large values to read
7b7a060e
AZ
325 * the cmdline. */
326 if (setrlimit(RLIMIT_STACK, &RLIMIT_MAKE_CONST(RLIM_INFINITY)) < 0)
327 log_warning("Testing without RLIMIT_STACK=infinity");
328
39782096 329 ASSERT_OK_ERRNO(unlink(path));
69281c49 330
39782096 331 ASSERT_OK_ERRNO(prctl(PR_SET_NAME, "testa"));
69281c49 332
39782096 333 ASSERT_ERROR(pid_get_cmdline(0, SIZE_MAX, 0, &line), ENOENT);
69281c49 334
39782096 335 ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &line));
daceaabe 336 log_debug("'%s'", line);
c79e88b3 337 ASSERT_STREQ(line, "[testa]");
69281c49
LP
338 line = mfree(line);
339
39782096 340 ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK | PROCESS_CMDLINE_QUOTE, &line));
daceaabe 341 log_debug("'%s'", line);
c79e88b3 342 ASSERT_STREQ(line, "\"[testa]\""); /* quoting is enabled here */
61977664
ZJS
343 line = mfree(line);
344
39782096 345 ASSERT_OK(pid_get_cmdline(0, 0, PROCESS_CMDLINE_COMM_FALLBACK, &line));
daceaabe 346 log_debug("'%s'", line);
c79e88b3 347 ASSERT_STREQ(line, "");
69281c49
LP
348 line = mfree(line);
349
39782096 350 ASSERT_OK(pid_get_cmdline(0, 1, PROCESS_CMDLINE_COMM_FALLBACK, &line));
c79e88b3 351 ASSERT_STREQ(line, "…");
bc28751e
ZJS
352 line = mfree(line);
353
39782096 354 ASSERT_OK(pid_get_cmdline(0, 2, PROCESS_CMDLINE_COMM_FALLBACK, &line));
c79e88b3 355 ASSERT_STREQ(line, "[…");
69281c49
LP
356 line = mfree(line);
357
39782096 358 ASSERT_OK(pid_get_cmdline(0, 3, PROCESS_CMDLINE_COMM_FALLBACK, &line));
c79e88b3 359 ASSERT_STREQ(line, "[t…");
69281c49
LP
360 line = mfree(line);
361
39782096 362 ASSERT_OK(pid_get_cmdline(0, 4, PROCESS_CMDLINE_COMM_FALLBACK, &line));
c79e88b3 363 ASSERT_STREQ(line, "[te…");
69281c49
LP
364 line = mfree(line);
365
39782096 366 ASSERT_OK(pid_get_cmdline(0, 5, PROCESS_CMDLINE_COMM_FALLBACK, &line));
c79e88b3 367 ASSERT_STREQ(line, "[tes…");
69281c49
LP
368 line = mfree(line);
369
39782096 370 ASSERT_OK(pid_get_cmdline(0, 6, PROCESS_CMDLINE_COMM_FALLBACK, &line));
c79e88b3 371 ASSERT_STREQ(line, "[test…");
69281c49
LP
372 line = mfree(line);
373
39782096 374 ASSERT_OK(pid_get_cmdline(0, 7, PROCESS_CMDLINE_COMM_FALLBACK, &line));
c79e88b3 375 ASSERT_STREQ(line, "[testa]");
69281c49
LP
376 line = mfree(line);
377
39782096 378 ASSERT_OK(pid_get_cmdline(0, 8, PROCESS_CMDLINE_COMM_FALLBACK, &line));
c79e88b3 379 ASSERT_STREQ(line, "[testa]");
69281c49
LP
380 line = mfree(line);
381
39782096
DDM
382 ASSERT_OK(pid_get_cmdline_strv(0, PROCESS_CMDLINE_COMM_FALLBACK, &args));
383 ASSERT_TRUE(strv_equal(args, STRV_MAKE("[testa]")));
201423d8
YW
384 args = strv_free(args);
385
61977664
ZJS
386 /* Test with multiple arguments that don't require quoting */
387
39782096 388 ASSERT_OK_EQ_ERRNO(write(fd, "foo\0bar", 8), 8);
69281c49 389
39782096 390 ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, 0, &line));
daceaabe 391 log_debug("'%s'", line);
c79e88b3 392 ASSERT_STREQ(line, "foo bar");
69281c49
LP
393 line = mfree(line);
394
39782096 395 ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &line));
c79e88b3 396 ASSERT_STREQ(line, "foo bar");
69281c49
LP
397 line = mfree(line);
398
39782096
DDM
399 ASSERT_OK(pid_get_cmdline_strv(0, PROCESS_CMDLINE_COMM_FALLBACK, &args));
400 ASSERT_TRUE(strv_equal(args, STRV_MAKE("foo", "bar")));
201423d8
YW
401 args = strv_free(args);
402
39782096
DDM
403 ASSERT_OK_EQ_ERRNO(write(fd, "quux", 4), 4);
404 ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, 0, &line));
daceaabe 405 log_debug("'%s'", line);
c79e88b3 406 ASSERT_STREQ(line, "foo bar quux");
69281c49
LP
407 line = mfree(line);
408
39782096 409 ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &line));
daceaabe 410 log_debug("'%s'", line);
c79e88b3 411 ASSERT_STREQ(line, "foo bar quux");
69281c49
LP
412 line = mfree(line);
413
39782096 414 ASSERT_OK(pid_get_cmdline(0, 1, PROCESS_CMDLINE_COMM_FALLBACK, &line));
daceaabe 415 log_debug("'%s'", line);
c79e88b3 416 ASSERT_STREQ(line, "…");
69281c49
LP
417 line = mfree(line);
418
39782096 419 ASSERT_OK(pid_get_cmdline(0, 2, PROCESS_CMDLINE_COMM_FALLBACK, &line));
daceaabe 420 log_debug("'%s'", line);
c79e88b3 421 ASSERT_STREQ(line, "f…");
69281c49
LP
422 line = mfree(line);
423
39782096 424 ASSERT_OK(pid_get_cmdline(0, 3, PROCESS_CMDLINE_COMM_FALLBACK, &line));
daceaabe 425 log_debug("'%s'", line);
c79e88b3 426 ASSERT_STREQ(line, "fo…");
69281c49
LP
427 line = mfree(line);
428
39782096 429 ASSERT_OK(pid_get_cmdline(0, 4, PROCESS_CMDLINE_COMM_FALLBACK, &line));
daceaabe 430 log_debug("'%s'", line);
c79e88b3 431 ASSERT_STREQ(line, "foo…");
69281c49
LP
432 line = mfree(line);
433
39782096 434 ASSERT_OK(pid_get_cmdline(0, 5, PROCESS_CMDLINE_COMM_FALLBACK, &line));
daceaabe 435 log_debug("'%s'", line);
c79e88b3 436 ASSERT_STREQ(line, "foo …");
69281c49
LP
437 line = mfree(line);
438
39782096 439 ASSERT_OK(pid_get_cmdline(0, 6, PROCESS_CMDLINE_COMM_FALLBACK, &line));
daceaabe 440 log_debug("'%s'", line);
c79e88b3 441 ASSERT_STREQ(line, "foo b…");
69281c49
LP
442 line = mfree(line);
443
39782096 444 ASSERT_OK(pid_get_cmdline(0, 7, PROCESS_CMDLINE_COMM_FALLBACK, &line));
daceaabe 445 log_debug("'%s'", line);
c79e88b3 446 ASSERT_STREQ(line, "foo ba…");
69281c49
LP
447 line = mfree(line);
448
39782096 449 ASSERT_OK(pid_get_cmdline(0, 8, PROCESS_CMDLINE_COMM_FALLBACK, &line));
daceaabe 450 log_debug("'%s'", line);
c79e88b3 451 ASSERT_STREQ(line, "foo bar…");
69281c49
LP
452 line = mfree(line);
453
39782096 454 ASSERT_OK(pid_get_cmdline(0, 9, PROCESS_CMDLINE_COMM_FALLBACK, &line));
daceaabe 455 log_debug("'%s'", line);
c79e88b3 456 ASSERT_STREQ(line, "foo bar …");
69281c49
LP
457 line = mfree(line);
458
39782096 459 ASSERT_OK(pid_get_cmdline(0, 10, PROCESS_CMDLINE_COMM_FALLBACK, &line));
daceaabe 460 log_debug("'%s'", line);
c79e88b3 461 ASSERT_STREQ(line, "foo bar q…");
69281c49
LP
462 line = mfree(line);
463
39782096 464 ASSERT_OK(pid_get_cmdline(0, 11, PROCESS_CMDLINE_COMM_FALLBACK, &line));
daceaabe 465 log_debug("'%s'", line);
c79e88b3 466 ASSERT_STREQ(line, "foo bar qu…");
69281c49
LP
467 line = mfree(line);
468
39782096 469 ASSERT_OK(pid_get_cmdline(0, 12, PROCESS_CMDLINE_COMM_FALLBACK, &line));
daceaabe 470 log_debug("'%s'", line);
c79e88b3 471 ASSERT_STREQ(line, "foo bar quux");
69281c49
LP
472 line = mfree(line);
473
39782096 474 ASSERT_OK(pid_get_cmdline(0, 13, PROCESS_CMDLINE_COMM_FALLBACK, &line));
daceaabe 475 log_debug("'%s'", line);
c79e88b3 476 ASSERT_STREQ(line, "foo bar quux");
69281c49
LP
477 line = mfree(line);
478
39782096 479 ASSERT_OK(pid_get_cmdline(0, 14, PROCESS_CMDLINE_COMM_FALLBACK, &line));
daceaabe 480 log_debug("'%s'", line);
c79e88b3 481 ASSERT_STREQ(line, "foo bar quux");
69281c49
LP
482 line = mfree(line);
483
39782096 484 ASSERT_OK(pid_get_cmdline(0, 1000, PROCESS_CMDLINE_COMM_FALLBACK, &line));
daceaabe 485 log_debug("'%s'", line);
c79e88b3 486 ASSERT_STREQ(line, "foo bar quux");
69281c49
LP
487 line = mfree(line);
488
39782096
DDM
489 ASSERT_OK(pid_get_cmdline_strv(0, PROCESS_CMDLINE_COMM_FALLBACK, &args));
490 ASSERT_TRUE(strv_equal(args, STRV_MAKE("foo", "bar", "quux")));
201423d8
YW
491 args = strv_free(args);
492
39782096
DDM
493 ASSERT_OK_ERRNO(ftruncate(fd, 0));
494 ASSERT_OK_ERRNO(prctl(PR_SET_NAME, "aaaa bbbb cccc"));
69281c49 495
39782096 496 ASSERT_ERROR(pid_get_cmdline(0, SIZE_MAX, 0, &line), ENOENT);
69281c49 497
39782096 498 ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &line));
daceaabe 499 log_debug("'%s'", line);
c79e88b3 500 ASSERT_STREQ(line, "[aaaa bbbb cccc]");
69281c49
LP
501 line = mfree(line);
502
39782096 503 ASSERT_OK(pid_get_cmdline(0, 10, PROCESS_CMDLINE_COMM_FALLBACK, &line));
daceaabe 504 log_debug("'%s'", line);
c79e88b3 505 ASSERT_STREQ(line, "[aaaa bbb…");
69281c49
LP
506 line = mfree(line);
507
39782096 508 ASSERT_OK(pid_get_cmdline(0, 11, PROCESS_CMDLINE_COMM_FALLBACK, &line));
daceaabe 509 log_debug("'%s'", line);
c79e88b3 510 ASSERT_STREQ(line, "[aaaa bbbb…");
69281c49
LP
511 line = mfree(line);
512
39782096 513 ASSERT_OK(pid_get_cmdline(0, 12, PROCESS_CMDLINE_COMM_FALLBACK, &line));
daceaabe 514 log_debug("'%s'", line);
c79e88b3 515 ASSERT_STREQ(line, "[aaaa bbbb …");
69281c49
LP
516 line = mfree(line);
517
39782096
DDM
518 ASSERT_OK(pid_get_cmdline_strv(0, PROCESS_CMDLINE_COMM_FALLBACK, &args));
519 ASSERT_TRUE(strv_equal(args, STRV_MAKE("[aaaa bbbb cccc]")));
201423d8
YW
520 args = strv_free(args);
521
61977664
ZJS
522 /* Test with multiple arguments that do require quoting */
523
524#define CMDLINE1 "foo\0'bar'\0\"bar$\"\0x y z\0!``\0"
aa9de5b1 525#define EXPECT1 "foo \"'bar'\" \"\\\"bar\\$\\\"\" \"x y z\" \"!\\`\\`\""
201423d8
YW
526#define EXPECT1p "foo $'\\'bar\\'' $'\"bar$\"' $'x y z' $'!``'"
527#define EXPECT1v STRV_MAKE("foo", "'bar'", "\"bar$\"", "x y z", "!``")
528
39782096
DDM
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)));
61977664 532
39782096 533 ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_QUOTE, &line));
daceaabe
ZJS
534 log_debug("got: ==%s==", line);
535 log_debug("exp: ==%s==", EXPECT1);
c79e88b3 536 ASSERT_STREQ(line, EXPECT1);
61977664
ZJS
537 line = mfree(line);
538
39782096 539 ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_QUOTE_POSIX, &line));
99009ed0
ZJS
540 log_debug("got: ==%s==", line);
541 log_debug("exp: ==%s==", EXPECT1p);
c79e88b3 542 ASSERT_STREQ(line, EXPECT1p);
99009ed0
ZJS
543 line = mfree(line);
544
39782096
DDM
545 ASSERT_OK(pid_get_cmdline_strv(0, 0, &args));
546 ASSERT_TRUE(strv_equal(args, EXPECT1v));
201423d8
YW
547 args = strv_free(args);
548
61977664 549#define CMDLINE2 "foo\0\1\2\3\0\0"
aa9de5b1 550#define EXPECT2 "foo \"\\001\\002\\003\""
201423d8
YW
551#define EXPECT2p "foo $'\\001\\002\\003'"
552#define EXPECT2v STRV_MAKE("foo", "\1\2\3")
553
39782096
DDM
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));
61977664 557
39782096 558 ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_QUOTE, &line));
daceaabe
ZJS
559 log_debug("got: ==%s==", line);
560 log_debug("exp: ==%s==", EXPECT2);
c79e88b3 561 ASSERT_STREQ(line, EXPECT2);
61977664
ZJS
562 line = mfree(line);
563
39782096 564 ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_QUOTE_POSIX, &line));
99009ed0
ZJS
565 log_debug("got: ==%s==", line);
566 log_debug("exp: ==%s==", EXPECT2p);
c79e88b3 567 ASSERT_STREQ(line, EXPECT2p);
99009ed0
ZJS
568 line = mfree(line);
569
39782096
DDM
570 ASSERT_OK(pid_get_cmdline_strv(0, 0, &args));
571 ASSERT_TRUE(strv_equal(args, EXPECT2v));
201423d8
YW
572 args = strv_free(args);
573
69281c49 574 safe_close(fd);
a45d7127 575 _exit(EXIT_SUCCESS);
69281c49
LP
576}
577
c462e63e 578TEST(getpid_cached) {
5c30a6d2
LP
579 siginfo_t si;
580 pid_t a, b, c, d, e, f, child;
581
33db9f21 582 a = getpid();
5c30a6d2
LP
583 b = getpid_cached();
584 c = getpid();
585
39782096
DDM
586 ASSERT_EQ(a, b);
587 ASSERT_EQ(a, c);
5c30a6d2
LP
588
589 child = fork();
39782096 590 ASSERT_OK_ERRNO(child);
5c30a6d2
LP
591
592 if (child == 0) {
593 /* In child */
33db9f21 594 a = getpid();
5c30a6d2
LP
595 b = getpid_cached();
596 c = getpid();
597
39782096
DDM
598 ASSERT_EQ(a, b);
599 ASSERT_EQ(a, c);
a45d7127 600 _exit(EXIT_SUCCESS);
5c30a6d2
LP
601 }
602
33db9f21 603 d = getpid();
5c30a6d2
LP
604 e = getpid_cached();
605 f = getpid();
606
39782096
DDM
607 ASSERT_EQ(a, d);
608 ASSERT_EQ(a, e);
609 ASSERT_EQ(a, f);
5c30a6d2 610
39782096
DDM
611 ASSERT_OK(wait_for_terminate(child, &si));
612 ASSERT_EQ(si.si_status, 0);
613 ASSERT_EQ(si.si_code, CLD_EXITED);
5c30a6d2
LP
614}
615
c462e63e 616TEST(getpid_measure) {
5c30a6d2
LP
617 usec_t t, q;
618
07468a16
ZJS
619 unsigned long long iterations = slow_tests_enabled() ? 1000000 : 1000;
620
621 log_info("/* %s (%llu iterations) */", __func__, iterations);
daceaabe 622
5c30a6d2 623 t = now(CLOCK_MONOTONIC);
07468a16 624 for (unsigned long long i = 0; i < iterations; i++)
5c30a6d2
LP
625 (void) getpid();
626 q = now(CLOCK_MONOTONIC) - t;
627
0c13daee 628 log_info(" glibc getpid(): %lf μs each", (double) q / iterations);
07468a16
ZJS
629
630 iterations *= 50; /* _cached() is about 50 times faster, so we need more iterations */
5c30a6d2
LP
631
632 t = now(CLOCK_MONOTONIC);
07468a16 633 for (unsigned long long i = 0; i < iterations; i++)
5c30a6d2
LP
634 (void) getpid_cached();
635 q = now(CLOCK_MONOTONIC) - t;
636
0c13daee 637 log_info("getpid_cached(): %lf μs each", (double) q / iterations);
5c30a6d2
LP
638}
639
c462e63e 640TEST(safe_fork) {
4c253ed1
LP
641 siginfo_t status;
642 pid_t pid;
643 int r;
644
645 BLOCK_SIGNALS(SIGCHLD);
646
e9ccae31 647 r = safe_fork("(test-child)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_REARRANGE_STDIO|FORK_REOPEN_LOG, &pid);
39782096 648 ASSERT_OK(r);
4c253ed1
LP
649
650 if (r == 0) {
651 /* child */
4251512e 652 usleep_safe(100 * USEC_PER_MSEC);
4c253ed1
LP
653
654 _exit(88);
655 }
656
39782096
DDM
657 ASSERT_OK(wait_for_terminate(pid, &status));
658 ASSERT_EQ(status.si_code, CLD_EXITED);
659 ASSERT_EQ(status.si_status, 88);
dc2f960b
DDM
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());
4c253ed1
LP
678}
679
c462e63e 680TEST(pid_to_ptr) {
39782096 681 ASSERT_EQ(PTR_TO_PID(NULL), 0);
5152b845 682 ASSERT_NULL(PID_TO_PTR(0));
eb5eb254 683
39782096
DDM
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);
eb5eb254 688
39782096
DDM
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);
eb5eb254 691
39782096
DDM
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);
eb5eb254
LP
694}
695
543497fa 696static void test_ioprio_class_from_to_string_one(const char *val, int expected, int normalized) {
39782096 697 ASSERT_EQ(ioprio_class_from_string(val), expected);
10062bbc
ZJS
698 if (expected >= 0) {
699 _cleanup_free_ char *s = NULL;
700 unsigned ret;
543497fa 701 int combined;
10062bbc 702
39782096 703 ASSERT_OK_ZERO(ioprio_class_to_string_alloc(expected, &s));
543497fa 704 /* We sometimes get a class number and sometimes a name back */
39782096 705 ASSERT_TRUE(streq(s, val) || safe_atou(val, &ret) == 0);
543497fa
LP
706
707 /* Make sure normalization works, i.e. NONE → BE gets normalized */
708 combined = ioprio_normalize(ioprio_prio_value(expected, 0));
39782096
DDM
709 ASSERT_EQ(ioprio_prio_class(combined), normalized);
710 ASSERT_TRUE(expected != IOPRIO_CLASS_NONE || ioprio_prio_data(combined) == 4);
10062bbc
ZJS
711 }
712}
9bfaffd5 713
c462e63e 714TEST(ioprio_class_from_to_string) {
543497fa
LP
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);
e7e91769 722 test_ioprio_class_from_to_string_one("8", -EINVAL, -EINVAL);
543497fa
LP
723 test_ioprio_class_from_to_string_one("9", -EINVAL, -EINVAL);
724 test_ioprio_class_from_to_string_one("-1", -EINVAL, -EINVAL);
10062bbc
ZJS
725}
726
c462e63e 727TEST(setpriority_closest) {
75997c3f
LP
728 int r;
729
daceaabe 730 r = safe_fork("(test-setprio)",
34a7ca6d 731 FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_WAIT|FORK_LOG|FORK_REOPEN_LOG, NULL);
39782096 732 ASSERT_OK(r);
75997c3f
LP
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) {
6a6078a5 741 /* If this fails we are probably unprivileged or in a userns of some kind, let's skip
75997c3f 742 * the full test */
39782096
DDM
743 if (!ERRNO_IS_PRIVILEGE(errno))
744 ASSERT_OK_ERRNO(-1);
75997c3f
LP
745 full_test = false;
746 } else {
92172554
DN
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) {
e5c6dcac
DDM
750 /* If the nobody user does not exist (user namespace) we get EINVAL. */
751 if (!ERRNO_IS_PRIVILEGE(errno) && errno != EINVAL)
39782096 752 ASSERT_OK_ERRNO(-1);
92172554
DN
753 full_test = false;
754 } else if (setresuid(UID_NOBODY, UID_NOBODY, UID_NOBODY) < 0) {
e5c6dcac
DDM
755 /* If the nobody user does not exist (user namespace) we get EINVAL. */
756 if (!ERRNO_IS_PRIVILEGE(errno) && errno != EINVAL)
39782096 757 ASSERT_OK_ERRNO(-1);
92172554
DN
758 full_test = false;
759 } else
760 full_test = true;
75997c3f
LP
761 }
762
763 errno = 0;
764 p = getpriority(PRIO_PROCESS, 0);
39782096 765 ASSERT_EQ(errno, 0);
75997c3f
LP
766
767 /* It should always be possible to set our nice level to the current one */
39782096 768 ASSERT_OK_POSITIVE(setpriority_closest(p));
75997c3f
LP
769
770 errno = 0;
771 q = getpriority(PRIO_PROCESS, 0);
39782096
DDM
772 ASSERT_EQ(errno, 0);
773 ASSERT_EQ(p, q);
75997c3f 774
cd990847 775 /* It should also be possible to set the nice level to one higher */
75997c3f 776 if (p < PRIO_MAX-1) {
39782096 777 ASSERT_OK_POSITIVE(setpriority_closest(++p));
75997c3f
LP
778
779 errno = 0;
780 q = getpriority(PRIO_PROCESS, 0);
39782096
DDM
781 ASSERT_EQ(errno, 0);
782 ASSERT_EQ(p, q);
75997c3f
LP
783 }
784
cd990847 785 /* It should also be possible to set the nice level to two higher */
75997c3f 786 if (p < PRIO_MAX-1) {
39782096 787 ASSERT_OK_POSITIVE(setpriority_closest(++p));
75997c3f
LP
788
789 errno = 0;
790 q = getpriority(PRIO_PROCESS, 0);
39782096
DDM
791 ASSERT_EQ(errno, 0);
792 ASSERT_EQ(p, q);
75997c3f
LP
793 }
794
795 if (full_test) {
796 /* These two should work, given the RLIMIT_NICE we set above */
39782096 797 ASSERT_OK_POSITIVE(setpriority_closest(-10));
75997c3f
LP
798 errno = 0;
799 q = getpriority(PRIO_PROCESS, 0);
39782096
DDM
800 ASSERT_EQ(errno, 0);
801 ASSERT_EQ(q, -10);
75997c3f 802
39782096 803 ASSERT_OK_POSITIVE(setpriority_closest(-9));
75997c3f
LP
804 errno = 0;
805 q = getpriority(PRIO_PROCESS, 0);
39782096
DDM
806 ASSERT_EQ(errno, 0);
807 ASSERT_EQ(q, -9);
75997c3f
LP
808
809 /* This should succeed but should be clamped to the limit */
39782096 810 ASSERT_OK_ZERO(setpriority_closest(-11));
75997c3f
LP
811 errno = 0;
812 q = getpriority(PRIO_PROCESS, 0);
39782096
DDM
813 ASSERT_EQ(errno, 0);
814 ASSERT_EQ(q, -10);
75997c3f 815
39782096 816 ASSERT_OK_POSITIVE(setpriority_closest(-8));
75997c3f
LP
817 errno = 0;
818 q = getpriority(PRIO_PROCESS, 0);
39782096
DDM
819 ASSERT_EQ(errno, 0);
820 ASSERT_EQ(q, -8);
75997c3f
LP
821
822 /* This should succeed but should be clamped to the limit */
39782096 823 ASSERT_OK_ZERO(setpriority_closest(-12));
75997c3f
LP
824 errno = 0;
825 q = getpriority(PRIO_PROCESS, 0);
39782096
DDM
826 ASSERT_EQ(errno, 0);
827 ASSERT_EQ(q, -10);
75997c3f
LP
828 }
829
830 _exit(EXIT_SUCCESS);
831 }
832}
833
47f64104 834TEST(pid_get_ppid) {
0c4d1e6d
LP
835 uint64_t limit;
836 int r;
837
47f64104 838 ASSERT_ERROR(pid_get_ppid(1, NULL), EADDRNOTAVAIL);
0c4d1e6d
LP
839
840 /* the process with the PID above the global limit definitely doesn't exist. Verify that */
39782096 841 ASSERT_OK(procfs_get_pid_max(&limit));
c3dead53
ZJS
842 log_debug("kernel.pid_max = %"PRIu64, limit);
843
844 if (limit < INT_MAX) {
47f64104 845 r = pid_get_ppid(limit + 1, NULL);
c3dead53
ZJS
846 log_debug_errno(r, "get_process_limit(%"PRIu64") → %d/%m", limit + 1, r);
847 assert(r == -ESRCH);
848 }
0c4d1e6d
LP
849
850 for (pid_t pid = 0;;) {
851 _cleanup_free_ char *c1 = NULL, *c2 = NULL;
852 pid_t ppid;
853
47f64104 854 r = pid_get_ppid(pid, &ppid);
0c4d1e6d
LP
855 if (r == -EADDRNOTAVAIL) {
856 log_info("No further parent PID");
857 break;
858 }
859
39782096 860 ASSERT_OK(r);
0c4d1e6d 861
39782096
DDM
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));
0c4d1e6d
LP
864
865 log_info("Parent of " PID_FMT " (%s) is " PID_FMT " (%s).", pid, c1, ppid, c2);
866
867 pid = ppid;
868 }
9237a63a
LP
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 }
0c4d1e6d
LP
892}
893
c462e63e 894TEST(set_oom_score_adjust) {
bb2d1d8e
LP
895 int a, b, r;
896
39782096 897 ASSERT_OK(get_oom_score_adjust(&a));
bb2d1d8e
LP
898
899 r = set_oom_score_adjust(OOM_SCORE_ADJ_MIN);
39782096
DDM
900 if (!ERRNO_IS_PRIVILEGE(r))
901 ASSERT_OK(r);
bb2d1d8e
LP
902
903 if (r >= 0) {
39782096
DDM
904 ASSERT_OK(get_oom_score_adjust(&b));
905 ASSERT_EQ(b, OOM_SCORE_ADJ_MIN);
bb2d1d8e
LP
906 }
907
39782096
DDM
908 ASSERT_OK(set_oom_score_adjust(a));
909 ASSERT_OK(get_oom_score_adjust(&b));
910 ASSERT_EQ(b, a);
bb2d1d8e
LP
911}
912
6aa90884
LP
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 */
39782096 918 ASSERT_OK_EQ_ERRNO(write(fd, &(const char) { 'x' }, 1), 1);
6aa90884
LP
919
920 /* wait for the main thread to tell us to shut down */
39782096 921 ASSERT_OK_EQ_ERRNO(read(fd, &x, 1), 1);
6aa90884
LP
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 */
34a7ca6d 929 r = safe_fork("(nthreads)", FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGTERM|FORK_WAIT|FORK_LOG, NULL);
39782096 930 ASSERT_OK(r);
6aa90884
LP
931
932 if (r == 0) {
71136404 933 _cleanup_close_pair_ int pfd[2] = EBADF_PAIR, ppfd[2] = EBADF_PAIR;
6aa90884
LP
934 pthread_t t, tt;
935 char x;
936
39782096
DDM
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));
6aa90884 939
39782096
DDM
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);
6aa90884 947
39782096
DDM
948 ASSERT_OK_EQ_ERRNO(write(pfd[1], &(const char) { 'x' }, 1), 1);
949 ASSERT_OK_ZERO_ERRNO(pthread_join(t, NULL));
6aa90884
LP
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 */
39782096
DDM
954 r = get_process_threads(0);
955 ASSERT_OK(r);
956 ASSERT_GE(r, 2);
6aa90884 957
39782096
DDM
958 ASSERT_OK_EQ_ERRNO(write(ppfd[1], &(const char) { 'x' }, 1), 1);
959 ASSERT_OK_ZERO_ERRNO(pthread_join(tt, NULL));
6aa90884
LP
960
961 /* similar here */
39782096
DDM
962 r = get_process_threads(0);
963 ASSERT_OK(r);
964 ASSERT_GE(r, 1);
6aa90884
LP
965
966 _exit(EXIT_SUCCESS);
967 }
968}
969
09f9530b
LP
970TEST(is_reaper_process) {
971 int r;
972
34a7ca6d 973 r = safe_fork("(regular)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_REOPEN_LOG|FORK_WAIT, NULL);
39782096 974 ASSERT_OK(r);
09f9530b
LP
975 if (r == 0) {
976 /* child */
977
39782096 978 ASSERT_OK_ZERO(is_reaper_process());
09f9530b
LP
979 _exit(EXIT_SUCCESS);
980 }
981
34a7ca6d 982 r = safe_fork("(newpid)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_REOPEN_LOG|FORK_WAIT, NULL);
39782096 983 ASSERT_OK(r);
09f9530b
LP
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
34a7ca6d 994 r = safe_fork("(newpid1)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_REOPEN_LOG|FORK_WAIT, NULL);
39782096 995 ASSERT_OK(r);
09f9530b
LP
996 if (r == 0) {
997 /* grandchild, which is PID1 in a pidns */
39782096
DDM
998 ASSERT_OK_EQ(getpid_cached(), 1);
999 ASSERT_OK_POSITIVE(is_reaper_process());
09f9530b
LP
1000 _exit(EXIT_SUCCESS);
1001 }
1002
1003 _exit(EXIT_SUCCESS);
1004 }
1005
34a7ca6d 1006 r = safe_fork("(subreaper)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_REOPEN_LOG|FORK_WAIT, NULL);
39782096 1007 ASSERT_OK(r);
09f9530b
LP
1008 if (r == 0) {
1009 /* child */
39782096 1010 ASSERT_OK(make_reaper_process(true));
09f9530b 1011
39782096 1012 ASSERT_OK_POSITIVE(is_reaper_process());
09f9530b
LP
1013 _exit(EXIT_SUCCESS);
1014 }
1015}
1016
3dee63b7
LP
1017TEST(pid_get_start_time) {
1018 _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
1019
39782096 1020 ASSERT_OK(pidref_set_self(&pidref));
3dee63b7 1021
6fb97a85 1022 usec_t start_time;
39782096 1023 ASSERT_OK(pidref_get_start_time(&pidref, &start_time));
6fb97a85 1024 log_info("our starttime: " USEC_FMT, start_time);
3dee63b7
LP
1025
1026 _cleanup_(pidref_done_sigkill_wait) PidRef child = PIDREF_NULL;
1027
a65de78d 1028 ASSERT_OK_POSITIVE(pidref_safe_fork("(stub)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_REOPEN_LOG|FORK_FREEZE, &child));
3dee63b7 1029
6fb97a85 1030 usec_t start_time2;
39782096 1031 ASSERT_OK(pidref_get_start_time(&child, &start_time2));
3dee63b7 1032
6fb97a85 1033 log_info("child starttime: " USEC_FMT, start_time2);
3dee63b7 1034
39782096 1035 ASSERT_GE(start_time2, start_time);
3dee63b7
LP
1036}
1037
d6267b9b
LP
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
afede53a
LP
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
99839c7e
LP
1100static int intro(void) {
1101 log_show_color(true);
1102 return EXIT_SUCCESS;
1103}
1104
e85fdacc 1105DEFINE_TEST_MAIN_WITH_INTRO(LOG_INFO, intro);