]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/test/test-async.c
zsh: remove _files prefixes
[thirdparty/systemd.git] / src / test / test-async.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <fcntl.h>
4 #include <sys/wait.h>
5 #include <unistd.h>
6
7 #include "async.h"
8 #include "fs-util.h"
9 #include "path-util.h"
10 #include "pidref.h"
11 #include "process-util.h"
12 #include "rm-rf.h"
13 #include "signal-util.h"
14 #include "tests.h"
15 #include "time-util.h"
16 #include "tmpfile-util.h"
17
18 TEST(asynchronous_sync) {
19 _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
20 ASSERT_OK(asynchronous_sync(&pidref));
21 ASSERT_OK(pidref_wait_for_terminate(&pidref, /* ret= */ NULL));
22 }
23
24 static void wait_fd_closed(int fd) {
25 for (unsigned trial = 0; trial < 100; trial++) {
26 usleep_safe(100 * USEC_PER_MSEC);
27 if (fcntl(fd, F_GETFD) < 0) {
28 assert_se(errno == EBADF);
29 return;
30 }
31 }
32
33 assert_not_reached();
34 }
35
36 TEST(asynchronous_close) {
37 _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-asynchronous_close.XXXXXX";
38 int fd, r;
39
40 fd = mkostemp_safe(name);
41 ASSERT_OK(fd);
42 asynchronous_close(fd);
43 wait_fd_closed(fd);
44
45 r = safe_fork("(subreaper)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGKILL|FORK_LOG|FORK_WAIT, NULL);
46 ASSERT_OK(r);
47
48 if (r == 0) {
49 /* child */
50
51 ASSERT_OK(make_reaper_process(true));
52
53 fd = open("/dev/null", O_RDONLY|O_CLOEXEC);
54 ASSERT_OK(fd);
55 asynchronous_close(fd);
56 wait_fd_closed(fd);
57
58 _exit(EXIT_SUCCESS);
59 }
60 }
61
62 static void wait_rm_rf(const char *path) {
63 for (unsigned trial = 0; trial < 100; trial++) {
64 usleep_safe(100 * USEC_PER_MSEC);
65 if (access(path, F_OK) < 0) {
66 assert_se(errno == ENOENT);
67 return;
68 }
69 }
70
71 assert_not_reached();
72 }
73
74 TEST(asynchronous_rm_rf) {
75 _cleanup_free_ char *t = NULL, *k = NULL;
76 int r;
77
78 ASSERT_OK(mkdtemp_malloc(NULL, &t));
79 assert_se(k = path_join(t, "somefile"));
80 ASSERT_OK(touch(k));
81 ASSERT_OK(asynchronous_rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL));
82 wait_rm_rf(t);
83
84 /* Do this once more, from a subreaper. Which is nice, because we can watch the async child even
85 * though detached */
86
87 r = safe_fork("(subreaper)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_REOPEN_LOG|FORK_LOG|FORK_WAIT, NULL);
88 ASSERT_OK(r);
89
90 if (r == 0) {
91 _cleanup_free_ char *tt = NULL, *kk = NULL;
92
93 /* child */
94
95 ASSERT_OK(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD));
96 ASSERT_OK(make_reaper_process(true));
97
98 ASSERT_OK(mkdtemp_malloc(NULL, &tt));
99 assert_se(kk = path_join(tt, "somefile"));
100 ASSERT_OK(touch(kk));
101 ASSERT_OK(asynchronous_rm_rf(tt, REMOVE_ROOT|REMOVE_PHYSICAL));
102
103 for (;;) {
104 siginfo_t si = {};
105
106 ASSERT_OK_ERRNO(waitid(P_ALL, 0, &si, WEXITED));
107
108 if (access(tt, F_OK) < 0) {
109 assert_se(errno == ENOENT);
110 break;
111 }
112
113 /* wasn't the rm_rf() call. let's wait longer */
114 }
115
116 _exit(EXIT_SUCCESS);
117 }
118 }
119
120 DEFINE_TEST_MAIN(LOG_DEBUG);