2 This file is part of systemd.
4 Copyright 2010 Lennart Poettering
5 Copyright 2013 Thomas H.P. Andersen
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 #include <sys/mount.h>
23 #include <sys/personality.h>
24 #include <sys/prctl.h>
26 #include <sys/types.h>
29 #ifdef HAVE_VALGRIND_VALGRIND_H
30 #include <valgrind/valgrind.h>
33 #include "alloc-util.h"
34 //#include "architecture.h"
38 #include "parse-util.h"
39 #include "process-util.h"
40 #include "stdio-util.h"
41 #include "string-util.h"
42 #include "terminal-util.h"
43 #include "test-helper.h"
47 static void test_get_process_comm(pid_t pid) {
49 _cleanup_free_ char *a = NULL, *c = NULL, *d = NULL, *f = NULL, *i = NULL;
50 _cleanup_free_ char *env = NULL;
51 char path[strlen("/proc//comm") + DECIMAL_STR_MAX(pid_t)];
52 #if 0 /// UNNEEDED by elogind
60 xsprintf(path, "/proc/"PID_FMT"/comm", pid);
62 if (stat(path, &st) == 0) {
63 assert_se(get_process_comm(pid, &a) >= 0);
64 log_info("PID"PID_FMT" comm: '%s'", pid, a);
66 log_warning("%s not exist.", path);
68 assert_se(get_process_cmdline(pid, 0, true, &c) >= 0);
69 log_info("PID"PID_FMT" cmdline: '%s'", pid, c);
71 assert_se(get_process_cmdline(pid, 8, false, &d) >= 0);
72 log_info("PID"PID_FMT" cmdline truncated to 8: '%s'", pid, d);
75 assert_se(get_process_cmdline(pid, 1, false, &d) >= 0);
76 log_info("PID"PID_FMT" cmdline truncated to 1: '%s'", pid, d);
78 #if 0 /// UNNEEDED by elogind
79 assert_se(get_process_ppid(pid, &e) >= 0);
80 log_info("PID"PID_FMT" PPID: "PID_FMT, pid, e);
81 assert_se(pid == 1 ? e == 0 : e > 0);
84 assert_se(is_kernel_thread(pid) == 0 || pid != 1);
86 r = get_process_exe(pid, &f);
87 assert_se(r >= 0 || r == -EACCES);
88 log_info("PID"PID_FMT" exe: '%s'", pid, strna(f));
90 #if 0 /// UNNEEDED by elogind
91 assert_se(get_process_uid(pid, &u) == 0);
92 log_info("PID"PID_FMT" UID: "UID_FMT, pid, u);
93 assert_se(u == 0 || pid != 1);
95 assert_se(get_process_gid(pid, &g) == 0);
96 log_info("PID"PID_FMT" GID: "GID_FMT, pid, g);
97 assert_se(g == 0 || pid != 1);
99 r = get_process_environ(pid, &env);
100 assert_se(r >= 0 || r == -EACCES);
101 log_info("PID"PID_FMT" strlen(environ): %zi", pid, env ? (ssize_t)strlen(env) : (ssize_t)-errno);
104 if (!detect_container())
105 assert_se(get_ctty_devnr(pid, &h) == -ENXIO || pid != 1);
107 getenv_for_pid(pid, "PATH", &i);
108 log_info("PID"PID_FMT" $PATH: '%s'", pid, strna(i));
111 static void test_pid_is_unwaited(void) {
121 waitpid(pid, &status, 0);
122 assert_se(!pid_is_unwaited(pid));
124 assert_se(pid_is_unwaited(getpid_cached()));
125 assert_se(!pid_is_unwaited(-1));
128 static void test_pid_is_alive(void) {
138 waitpid(pid, &status, 0);
139 assert_se(!pid_is_alive(pid));
141 assert_se(pid_is_alive(getpid_cached()));
142 assert_se(!pid_is_alive(-1));
145 #if 0 /// UNNEEDED by elogind
146 static void test_personality(void) {
148 assert_se(personality_to_string(PER_LINUX));
149 assert_se(!personality_to_string(PERSONALITY_INVALID));
151 assert_se(streq(personality_to_string(PER_LINUX), architecture_to_string(native_architecture())));
153 assert_se(personality_from_string(personality_to_string(PER_LINUX)) == PER_LINUX);
154 assert_se(personality_from_string(architecture_to_string(native_architecture())) == PER_LINUX);
157 assert_se(streq_ptr(personality_to_string(PER_LINUX), "x86-64"));
158 assert_se(streq_ptr(personality_to_string(PER_LINUX32), "x86"));
160 assert_se(personality_from_string("x86-64") == PER_LINUX);
161 assert_se(personality_from_string("x86") == PER_LINUX32);
162 assert_se(personality_from_string("ia64") == PERSONALITY_INVALID);
163 assert_se(personality_from_string(NULL) == PERSONALITY_INVALID);
165 assert_se(personality_from_string(personality_to_string(PER_LINUX32)) == PER_LINUX32);
170 static void test_get_process_cmdline_harder(void) {
171 char path[] = "/tmp/test-cmdlineXXXXXX";
172 _cleanup_close_ int fd = -1;
173 _cleanup_free_ char *line = NULL;
179 #ifdef HAVE_VALGRIND_VALGRIND_H
180 /* valgrind patches open(/proc//cmdline)
181 * so, test_get_process_cmdline_harder fails always
182 * See https://github.com/systemd/systemd/pull/3555#issuecomment-226564908 */
183 if (RUNNING_ON_VALGRIND)
191 (void) wait_for_terminate(pid, &si);
193 assert_se(si.si_code == CLD_EXITED);
194 assert_se(si.si_status == 0);
200 assert_se(unshare(CLONE_NEWNS) >= 0);
202 fd = mkostemp(path, O_CLOEXEC);
205 if (mount(path, "/proc/self/cmdline", "bind", MS_BIND, NULL) < 0) {
206 /* This happens under selinux… Abort the test in this case. */
207 log_warning_errno(errno, "mount(..., \"/proc/self/cmdline\", \"bind\", ...) failed: %m");
208 assert(errno == EACCES);
212 assert_se(unlink(path) >= 0);
214 assert_se(prctl(PR_SET_NAME, "testa") >= 0);
216 assert_se(get_process_cmdline(getpid_cached(), 0, false, &line) == -ENOENT);
218 assert_se(get_process_cmdline(getpid_cached(), 0, true, &line) >= 0);
219 assert_se(streq(line, "[testa]"));
222 assert_se(get_process_cmdline(getpid_cached(), 1, true, &line) >= 0);
223 assert_se(streq(line, ""));
226 assert_se(get_process_cmdline(getpid_cached(), 2, true, &line) >= 0);
227 assert_se(streq(line, "["));
230 assert_se(get_process_cmdline(getpid_cached(), 3, true, &line) >= 0);
231 assert_se(streq(line, "[."));
234 assert_se(get_process_cmdline(getpid_cached(), 4, true, &line) >= 0);
235 assert_se(streq(line, "[.."));
238 assert_se(get_process_cmdline(getpid_cached(), 5, true, &line) >= 0);
239 assert_se(streq(line, "[..."));
242 assert_se(get_process_cmdline(getpid_cached(), 6, true, &line) >= 0);
243 assert_se(streq(line, "[...]"));
246 assert_se(get_process_cmdline(getpid_cached(), 7, true, &line) >= 0);
247 assert_se(streq(line, "[t...]"));
250 assert_se(get_process_cmdline(getpid_cached(), 8, true, &line) >= 0);
251 assert_se(streq(line, "[testa]"));
254 assert_se(write(fd, "\0\0\0\0\0\0\0\0\0", 10) == 10);
256 assert_se(get_process_cmdline(getpid_cached(), 0, false, &line) == -ENOENT);
258 assert_se(get_process_cmdline(getpid_cached(), 0, true, &line) >= 0);
259 assert_se(streq(line, "[testa]"));
262 assert_se(write(fd, "foo\0bar\0\0\0\0\0", 10) == 10);
264 assert_se(get_process_cmdline(getpid_cached(), 0, false, &line) >= 0);
265 assert_se(streq(line, "foo bar"));
268 assert_se(get_process_cmdline(getpid_cached(), 0, true, &line) >= 0);
269 assert_se(streq(line, "foo bar"));
272 assert_se(write(fd, "quux", 4) == 4);
273 assert_se(get_process_cmdline(getpid_cached(), 0, false, &line) >= 0);
274 assert_se(streq(line, "foo bar quux"));
277 assert_se(get_process_cmdline(getpid_cached(), 0, true, &line) >= 0);
278 assert_se(streq(line, "foo bar quux"));
281 assert_se(get_process_cmdline(getpid_cached(), 1, true, &line) >= 0);
282 assert_se(streq(line, ""));
285 assert_se(get_process_cmdline(getpid_cached(), 2, true, &line) >= 0);
286 assert_se(streq(line, "."));
289 assert_se(get_process_cmdline(getpid_cached(), 3, true, &line) >= 0);
290 assert_se(streq(line, ".."));
293 assert_se(get_process_cmdline(getpid_cached(), 4, true, &line) >= 0);
294 assert_se(streq(line, "..."));
297 assert_se(get_process_cmdline(getpid_cached(), 5, true, &line) >= 0);
298 assert_se(streq(line, "f..."));
301 assert_se(get_process_cmdline(getpid_cached(), 6, true, &line) >= 0);
302 assert_se(streq(line, "fo..."));
305 assert_se(get_process_cmdline(getpid_cached(), 7, true, &line) >= 0);
306 assert_se(streq(line, "foo..."));
309 assert_se(get_process_cmdline(getpid_cached(), 8, true, &line) >= 0);
310 assert_se(streq(line, "foo..."));
313 assert_se(get_process_cmdline(getpid_cached(), 9, true, &line) >= 0);
314 assert_se(streq(line, "foo b..."));
317 assert_se(get_process_cmdline(getpid_cached(), 10, true, &line) >= 0);
318 assert_se(streq(line, "foo ba..."));
321 assert_se(get_process_cmdline(getpid_cached(), 11, true, &line) >= 0);
322 assert_se(streq(line, "foo bar..."));
325 assert_se(get_process_cmdline(getpid_cached(), 12, true, &line) >= 0);
326 assert_se(streq(line, "foo bar..."));
329 assert_se(get_process_cmdline(getpid_cached(), 13, true, &line) >= 0);
330 assert_se(streq(line, "foo bar quux"));
333 assert_se(get_process_cmdline(getpid_cached(), 14, true, &line) >= 0);
334 assert_se(streq(line, "foo bar quux"));
337 assert_se(get_process_cmdline(getpid_cached(), 1000, true, &line) >= 0);
338 assert_se(streq(line, "foo bar quux"));
341 assert_se(ftruncate(fd, 0) >= 0);
342 assert_se(prctl(PR_SET_NAME, "aaaa bbbb cccc") >= 0);
344 assert_se(get_process_cmdline(getpid_cached(), 0, false, &line) == -ENOENT);
346 assert_se(get_process_cmdline(getpid_cached(), 0, true, &line) >= 0);
347 assert_se(streq(line, "[aaaa bbbb cccc]"));
350 assert_se(get_process_cmdline(getpid_cached(), 10, true, &line) >= 0);
351 assert_se(streq(line, "[aaaa...]"));
354 assert_se(get_process_cmdline(getpid_cached(), 11, true, &line) >= 0);
355 assert_se(streq(line, "[aaaa...]"));
358 assert_se(get_process_cmdline(getpid_cached(), 12, true, &line) >= 0);
359 assert_se(streq(line, "[aaaa b...]"));
366 #if 0 /// UNNEEDED by elogind
367 static void test_rename_process_now(const char *p, int ret) {
368 _cleanup_free_ char *comm = NULL, *cmdline = NULL;
371 r = rename_process(p);
372 assert_se(r == ret ||
373 (ret == 0 && r >= 0) ||
379 #ifdef HAVE_VALGRIND_VALGRIND_H
380 /* see above, valgrind is weird, we can't verify what we are doing here */
381 if (RUNNING_ON_VALGRIND)
385 assert_se(get_process_comm(0, &comm) >= 0);
386 log_info("comm = <%s>", comm);
387 assert_se(strneq(comm, p, 15));
389 assert_se(get_process_cmdline(0, 0, false, &cmdline) >= 0);
390 /* we cannot expect cmdline to be renamed properly without privileges */
391 if (geteuid() == 0) {
392 log_info("cmdline = <%s>", cmdline);
393 assert_se(strneq(p, cmdline, strlen("test-process-util")));
394 assert_se(startswith(p, cmdline));
396 log_info("cmdline = <%s> (not verified)", cmdline);
399 static void test_rename_process_one(const char *p, int ret) {
408 test_rename_process_now(p, ret);
412 assert_se(wait_for_terminate(pid, &si) >= 0);
413 assert_se(si.si_code == CLD_EXITED);
414 assert_se(si.si_status == EXIT_SUCCESS);
417 static void test_rename_process_multi(void) {
426 assert_se(wait_for_terminate(pid, &si) >= 0);
427 assert_se(si.si_code == CLD_EXITED);
428 assert_se(si.si_status == EXIT_SUCCESS);
434 test_rename_process_now("one", 1);
435 test_rename_process_now("more", 0); /* longer than "one", hence truncated */
436 setresuid(99, 99, 99);
437 test_rename_process_now("time!", 0);
438 test_rename_process_now("0", 1); /* shorter than "one", should fit */
439 test_rename_process_one("", -EINVAL);
440 test_rename_process_one(NULL, -EINVAL);
444 static void test_rename_process(void) {
445 test_rename_process_one(NULL, -EINVAL);
446 test_rename_process_one("", -EINVAL);
447 test_rename_process_one("foo", 1); /* should always fit */
448 test_rename_process_one("this is a really really long process name, followed by some more words", 0); /* unlikely to fit */
449 test_rename_process_one("1234567", 1); /* should always fit */
450 test_rename_process_multi(); /* multiple invocations and dropped privileges */
454 static void test_getpid_cached(void) {
456 pid_t a, b, c, d, e, f, child;
462 assert_se(a == b && a == c);
465 assert_se(child >= 0);
473 assert_se(a == b && a == c);
481 assert_se(a == d && a == e && a == f);
483 assert_se(wait_for_terminate(child, &si) >= 0);
484 assert_se(si.si_status == 0);
485 assert_se(si.si_code == CLD_EXITED);
488 #define MEASURE_ITERATIONS (10000000LLU)
490 static void test_getpid_measure(void) {
491 unsigned long long i;
494 t = now(CLOCK_MONOTONIC);
495 for (i = 0; i < MEASURE_ITERATIONS; i++)
497 q = now(CLOCK_MONOTONIC) - t;
499 log_info(" glibc getpid(): %llu/s\n", (unsigned long long) (MEASURE_ITERATIONS*USEC_PER_SEC/q));
501 t = now(CLOCK_MONOTONIC);
502 for (i = 0; i < MEASURE_ITERATIONS; i++)
503 (void) getpid_cached();
504 q = now(CLOCK_MONOTONIC) - t;
506 log_info("getpid_cached(): %llu/s\n", (unsigned long long) (MEASURE_ITERATIONS*USEC_PER_SEC/q));
509 int main(int argc, char *argv[]) {
511 log_set_max_level(LOG_DEBUG);
512 log_parse_environment();
521 (void) parse_pid(argv[1], &pid);
522 test_get_process_comm(pid);
524 TEST_REQ_RUNNING_SYSTEMD(test_get_process_comm(1));
525 test_get_process_comm(getpid());
528 test_pid_is_unwaited();
530 #if 0 /// UNNEEDED by elogind
533 test_get_process_cmdline_harder();
534 #if 0 /// UNNEEDED by elogind
535 test_rename_process();
537 test_getpid_cached();
538 test_getpid_measure();