chiark / gitweb /
Fix service file to match installed elogind binary location
[elogind.git] / src / test / test-process-util.c
1 /***
2   This file is part of systemd.
3
4   Copyright 2010 Lennart Poettering
5   Copyright 2013 Thomas H.P. Andersen
6
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.
11
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.
16
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/>.
19 ***/
20
21 #include <sched.h>
22 #include <sys/mount.h>
23 #include <sys/personality.h>
24 #include <sys/prctl.h>
25 #include <sys/stat.h>
26 #include <sys/types.h>
27 #include <sys/wait.h>
28 #include <unistd.h>
29 #ifdef HAVE_VALGRIND_VALGRIND_H
30 #include <valgrind/valgrind.h>
31 #endif
32
33 #include "alloc-util.h"
34 //#include "architecture.h"
35 #include "fd-util.h"
36 #include "log.h"
37 #include "macro.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"
44 #include "util.h"
45 #include "virt.h"
46
47 static void test_get_process_comm(pid_t pid) {
48         struct stat st;
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
53         pid_t e;
54         uid_t u;
55         gid_t g;
56 #endif // 0
57         dev_t h;
58         int r;
59
60         xsprintf(path, "/proc/"PID_FMT"/comm", pid);
61
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);
65         } else
66                 log_warning("%s not exist.", path);
67
68         assert_se(get_process_cmdline(pid, 0, true, &c) >= 0);
69         log_info("PID"PID_FMT" cmdline: '%s'", pid, c);
70
71         assert_se(get_process_cmdline(pid, 8, false, &d) >= 0);
72         log_info("PID"PID_FMT" cmdline truncated to 8: '%s'", pid, d);
73
74         free(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);
77
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);
82 #endif // 0
83
84         assert_se(is_kernel_thread(pid) == 0 || pid != 1);
85
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));
89
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);
94
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);
98
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);
102 #endif // 0
103
104         if (!detect_container())
105                 assert_se(get_ctty_devnr(pid, &h) == -ENXIO || pid != 1);
106
107         getenv_for_pid(pid, "PATH", &i);
108         log_info("PID"PID_FMT" $PATH: '%s'", pid, strna(i));
109 }
110
111 static void test_pid_is_unwaited(void) {
112         pid_t pid;
113
114         pid = fork();
115         assert_se(pid >= 0);
116         if (pid == 0) {
117                 _exit(EXIT_SUCCESS);
118         } else {
119                 int status;
120
121                 waitpid(pid, &status, 0);
122                 assert_se(!pid_is_unwaited(pid));
123         }
124         assert_se(pid_is_unwaited(getpid()));
125         assert_se(!pid_is_unwaited(-1));
126 }
127
128 static void test_pid_is_alive(void) {
129         pid_t pid;
130
131         pid = fork();
132         assert_se(pid >= 0);
133         if (pid == 0) {
134                 _exit(EXIT_SUCCESS);
135         } else {
136                 int status;
137
138                 waitpid(pid, &status, 0);
139                 assert_se(!pid_is_alive(pid));
140         }
141         assert_se(pid_is_alive(getpid()));
142         assert_se(!pid_is_alive(-1));
143 }
144
145 #if 0 /// UNNEEDED by elogind
146 static void test_personality(void) {
147
148         assert_se(personality_to_string(PER_LINUX));
149         assert_se(!personality_to_string(PERSONALITY_INVALID));
150
151         assert_se(streq(personality_to_string(PER_LINUX), architecture_to_string(native_architecture())));
152
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);
155
156 #ifdef __x86_64__
157         assert_se(streq_ptr(personality_to_string(PER_LINUX), "x86-64"));
158         assert_se(streq_ptr(personality_to_string(PER_LINUX32), "x86"));
159
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);
164
165         assert_se(personality_from_string(personality_to_string(PER_LINUX32)) == PER_LINUX32);
166 #endif
167 }
168 #endif // 0
169
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;
174         pid_t pid;
175
176         if (geteuid() != 0)
177                 return;
178
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)
184                 return;
185 #endif
186
187         pid = fork();
188         if (pid > 0) {
189                 siginfo_t si;
190
191                 (void) wait_for_terminate(pid, &si);
192
193                 assert_se(si.si_code == CLD_EXITED);
194                 assert_se(si.si_status == 0);
195
196                 return;
197         }
198
199         assert_se(pid == 0);
200         assert_se(unshare(CLONE_NEWNS) >= 0);
201
202         fd = mkostemp(path, O_CLOEXEC);
203         assert_se(fd >= 0);
204
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);
209                 return;
210         }
211
212         assert_se(unlink(path) >= 0);
213
214         assert_se(prctl(PR_SET_NAME, "testa") >= 0);
215
216         assert_se(get_process_cmdline(getpid(), 0, false, &line) == -ENOENT);
217
218         assert_se(get_process_cmdline(getpid(), 0, true, &line) >= 0);
219         assert_se(streq(line, "[testa]"));
220         line = mfree(line);
221
222         assert_se(get_process_cmdline(getpid(), 1, true, &line) >= 0);
223         assert_se(streq(line, ""));
224         line = mfree(line);
225
226         assert_se(get_process_cmdline(getpid(), 2, true, &line) >= 0);
227         assert_se(streq(line, "["));
228         line = mfree(line);
229
230         assert_se(get_process_cmdline(getpid(), 3, true, &line) >= 0);
231         assert_se(streq(line, "[."));
232         line = mfree(line);
233
234         assert_se(get_process_cmdline(getpid(), 4, true, &line) >= 0);
235         assert_se(streq(line, "[.."));
236         line = mfree(line);
237
238         assert_se(get_process_cmdline(getpid(), 5, true, &line) >= 0);
239         assert_se(streq(line, "[..."));
240         line = mfree(line);
241
242         assert_se(get_process_cmdline(getpid(), 6, true, &line) >= 0);
243         assert_se(streq(line, "[...]"));
244         line = mfree(line);
245
246         assert_se(get_process_cmdline(getpid(), 7, true, &line) >= 0);
247         assert_se(streq(line, "[t...]"));
248         line = mfree(line);
249
250         assert_se(get_process_cmdline(getpid(), 8, true, &line) >= 0);
251         assert_se(streq(line, "[testa]"));
252         line = mfree(line);
253
254         assert_se(write(fd, "\0\0\0\0\0\0\0\0\0", 10) == 10);
255
256         assert_se(get_process_cmdline(getpid(), 0, false, &line) == -ENOENT);
257
258         assert_se(get_process_cmdline(getpid(), 0, true, &line) >= 0);
259         assert_se(streq(line, "[testa]"));
260         line = mfree(line);
261
262         assert_se(write(fd, "foo\0bar\0\0\0\0\0", 10) == 10);
263
264         assert_se(get_process_cmdline(getpid(), 0, false, &line) >= 0);
265         assert_se(streq(line, "foo bar"));
266         line = mfree(line);
267
268         assert_se(get_process_cmdline(getpid(), 0, true, &line) >= 0);
269         assert_se(streq(line, "foo bar"));
270         line = mfree(line);
271
272         assert_se(write(fd, "quux", 4) == 4);
273         assert_se(get_process_cmdline(getpid(), 0, false, &line) >= 0);
274         assert_se(streq(line, "foo bar quux"));
275         line = mfree(line);
276
277         assert_se(get_process_cmdline(getpid(), 0, true, &line) >= 0);
278         assert_se(streq(line, "foo bar quux"));
279         line = mfree(line);
280
281         assert_se(get_process_cmdline(getpid(), 1, true, &line) >= 0);
282         assert_se(streq(line, ""));
283         line = mfree(line);
284
285         assert_se(get_process_cmdline(getpid(), 2, true, &line) >= 0);
286         assert_se(streq(line, "."));
287         line = mfree(line);
288
289         assert_se(get_process_cmdline(getpid(), 3, true, &line) >= 0);
290         assert_se(streq(line, ".."));
291         line = mfree(line);
292
293         assert_se(get_process_cmdline(getpid(), 4, true, &line) >= 0);
294         assert_se(streq(line, "..."));
295         line = mfree(line);
296
297         assert_se(get_process_cmdline(getpid(), 5, true, &line) >= 0);
298         assert_se(streq(line, "f..."));
299         line = mfree(line);
300
301         assert_se(get_process_cmdline(getpid(), 6, true, &line) >= 0);
302         assert_se(streq(line, "fo..."));
303         line = mfree(line);
304
305         assert_se(get_process_cmdline(getpid(), 7, true, &line) >= 0);
306         assert_se(streq(line, "foo..."));
307         line = mfree(line);
308
309         assert_se(get_process_cmdline(getpid(), 8, true, &line) >= 0);
310         assert_se(streq(line, "foo..."));
311         line = mfree(line);
312
313         assert_se(get_process_cmdline(getpid(), 9, true, &line) >= 0);
314         assert_se(streq(line, "foo b..."));
315         line = mfree(line);
316
317         assert_se(get_process_cmdline(getpid(), 10, true, &line) >= 0);
318         assert_se(streq(line, "foo ba..."));
319         line = mfree(line);
320
321         assert_se(get_process_cmdline(getpid(), 11, true, &line) >= 0);
322         assert_se(streq(line, "foo bar..."));
323         line = mfree(line);
324
325         assert_se(get_process_cmdline(getpid(), 12, true, &line) >= 0);
326         assert_se(streq(line, "foo bar..."));
327         line = mfree(line);
328
329         assert_se(get_process_cmdline(getpid(), 13, true, &line) >= 0);
330         assert_se(streq(line, "foo bar quux"));
331         line = mfree(line);
332
333         assert_se(get_process_cmdline(getpid(), 14, true, &line) >= 0);
334         assert_se(streq(line, "foo bar quux"));
335         line = mfree(line);
336
337         assert_se(get_process_cmdline(getpid(), 1000, true, &line) >= 0);
338         assert_se(streq(line, "foo bar quux"));
339         line = mfree(line);
340
341         assert_se(ftruncate(fd, 0) >= 0);
342         assert_se(prctl(PR_SET_NAME, "aaaa bbbb cccc") >= 0);
343
344         assert_se(get_process_cmdline(getpid(), 0, false, &line) == -ENOENT);
345
346         assert_se(get_process_cmdline(getpid(), 0, true, &line) >= 0);
347         assert_se(streq(line, "[aaaa bbbb cccc]"));
348         line = mfree(line);
349
350         assert_se(get_process_cmdline(getpid(), 10, true, &line) >= 0);
351         assert_se(streq(line, "[aaaa...]"));
352         line = mfree(line);
353
354         assert_se(get_process_cmdline(getpid(), 11, true, &line) >= 0);
355         assert_se(streq(line, "[aaaa...]"));
356         line = mfree(line);
357
358         assert_se(get_process_cmdline(getpid(), 12, true, &line) >= 0);
359         assert_se(streq(line, "[aaaa b...]"));
360         line = mfree(line);
361
362         safe_close(fd);
363         _exit(0);
364 }
365
366 #if 0 /// UNNEEDED by elogind
367 static void test_rename_process_one(const char *p, int ret) {
368         _cleanup_free_ char *comm = NULL, *cmdline = NULL;
369         pid_t pid;
370         int r;
371
372         pid = fork();
373         assert_se(pid >= 0);
374
375         if (pid > 0) {
376                 siginfo_t si;
377
378                 assert_se(wait_for_terminate(pid, &si) >= 0);
379                 assert_se(si.si_code == CLD_EXITED);
380                 assert_se(si.si_status == EXIT_SUCCESS);
381
382                 return;
383         }
384
385         /* child */
386         r = rename_process(p);
387
388         assert_se(r == ret ||
389                   (ret == 0 && r >= 0) ||
390                   (ret > 0 && r > 0));
391
392         if (r < 0)
393                 goto finish;
394
395 #ifdef HAVE_VALGRIND_VALGRIND_H
396         /* see above, valgrind is weird, we can't verify what we are doing here */
397         if (RUNNING_ON_VALGRIND)
398                 goto finish;
399 #endif
400
401         assert_se(get_process_comm(0, &comm) >= 0);
402         log_info("comm = <%s>", comm);
403         assert_se(strneq(comm, p, 15));
404
405         assert_se(get_process_cmdline(0, 0, false, &cmdline) >= 0);
406         log_info("cmdline = <%s>", cmdline);
407         assert_se(strneq(p, cmdline, strlen("test-process-util")));
408         assert_se(startswith(p, cmdline));
409
410 finish:
411         _exit(EXIT_SUCCESS);
412 }
413
414 static void test_rename_process(void) {
415         test_rename_process_one(NULL, -EINVAL);
416         test_rename_process_one("", -EINVAL);
417         test_rename_process_one("foo", 1); /* should always fit */
418         test_rename_process_one("this is a really really long process name, followed by some more words", 0); /* unlikely to fit */
419         test_rename_process_one("1234567", 1); /* should always fit */
420 }
421 #endif // 0
422
423 int main(int argc, char *argv[]) {
424
425         log_set_max_level(LOG_DEBUG);
426         log_parse_environment();
427         log_open();
428
429         saved_argc = argc;
430         saved_argv = argv;
431
432         if (argc > 1) {
433                 pid_t pid = 0;
434
435                 (void) parse_pid(argv[1], &pid);
436                 test_get_process_comm(pid);
437         } else {
438                 TEST_REQ_RUNNING_SYSTEMD(test_get_process_comm(1));
439                 test_get_process_comm(getpid());
440         }
441
442         test_pid_is_unwaited();
443         test_pid_is_alive();
444 #if 0 /// UNNEEDED by elogind
445         test_personality();
446 #endif // 0
447         test_get_process_cmdline_harder();
448 #if 0 /// UNNEEDED by elogind
449         test_rename_process();
450 #endif // 0
451
452         return 0;
453 }