]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/test/test-fd-util.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
6 #include "alloc-util.h"
10 #include "memory-util.h"
11 #include "path-util.h"
12 #include "process-util.h"
13 #include "random-util.h"
14 #include "rlimit-util.h"
15 #include "serialize.h"
16 #include "string-util.h"
18 #include "tmpfile-util.h"
20 static void test_close_many(void) {
22 char name0
[] = "/tmp/test-close-many.XXXXXX";
23 char name1
[] = "/tmp/test-close-many.XXXXXX";
24 char name2
[] = "/tmp/test-close-many.XXXXXX";
26 fds
[0] = mkostemp_safe(name0
);
27 fds
[1] = mkostemp_safe(name1
);
28 fds
[2] = mkostemp_safe(name2
);
32 assert_se(fcntl(fds
[0], F_GETFD
) == -1);
33 assert_se(fcntl(fds
[1], F_GETFD
) == -1);
34 assert_se(fcntl(fds
[2], F_GETFD
) >= 0);
43 static void test_close_nointr(void) {
44 char name
[] = "/tmp/test-test-close_nointr.XXXXXX";
47 fd
= mkostemp_safe(name
);
49 assert_se(close_nointr(fd
) >= 0);
50 assert_se(close_nointr(fd
) < 0);
55 static void test_same_fd(void) {
56 _cleanup_close_pair_
int p
[2] = { -1, -1 };
57 _cleanup_close_
int a
= -1, b
= -1, c
= -1;
59 assert_se(pipe2(p
, O_CLOEXEC
) >= 0);
60 assert_se((a
= fcntl(p
[0], F_DUPFD
, 3)) >= 0);
61 assert_se((b
= open("/dev/null", O_RDONLY
|O_CLOEXEC
)) >= 0);
62 assert_se((c
= fcntl(a
, F_DUPFD
, 3)) >= 0);
64 assert_se(same_fd(p
[0], p
[0]) > 0);
65 assert_se(same_fd(p
[1], p
[1]) > 0);
66 assert_se(same_fd(a
, a
) > 0);
67 assert_se(same_fd(b
, b
) > 0);
69 assert_se(same_fd(a
, p
[0]) > 0);
70 assert_se(same_fd(p
[0], a
) > 0);
71 assert_se(same_fd(c
, p
[0]) > 0);
72 assert_se(same_fd(p
[0], c
) > 0);
73 assert_se(same_fd(a
, c
) > 0);
74 assert_se(same_fd(c
, a
) > 0);
76 assert_se(same_fd(p
[0], p
[1]) == 0);
77 assert_se(same_fd(p
[1], p
[0]) == 0);
78 assert_se(same_fd(p
[0], b
) == 0);
79 assert_se(same_fd(b
, p
[0]) == 0);
80 assert_se(same_fd(p
[1], a
) == 0);
81 assert_se(same_fd(a
, p
[1]) == 0);
82 assert_se(same_fd(p
[1], b
) == 0);
83 assert_se(same_fd(b
, p
[1]) == 0);
85 assert_se(same_fd(a
, b
) == 0);
86 assert_se(same_fd(b
, a
) == 0);
89 static void test_open_serialization_fd(void) {
90 _cleanup_close_
int fd
= -1;
92 fd
= open_serialization_fd("test");
95 assert_se(write(fd
, "test\n", 5) == 5);
98 static void test_acquire_data_fd_one(unsigned flags
) {
99 char wbuffer
[196*1024 - 7];
100 char rbuffer
[sizeof(wbuffer
)];
103 fd
= acquire_data_fd("foo", 3, flags
);
107 assert_se(read(fd
, rbuffer
, sizeof(rbuffer
)) == 3);
108 assert_se(streq(rbuffer
, "foo"));
112 fd
= acquire_data_fd("", 0, flags
);
116 assert_se(read(fd
, rbuffer
, sizeof(rbuffer
)) == 0);
117 assert_se(streq(rbuffer
, ""));
121 random_bytes(wbuffer
, sizeof(wbuffer
));
123 fd
= acquire_data_fd(wbuffer
, sizeof(wbuffer
), flags
);
127 assert_se(read(fd
, rbuffer
, sizeof(rbuffer
)) == sizeof(rbuffer
));
128 assert_se(memcmp(rbuffer
, wbuffer
, sizeof(rbuffer
)) == 0);
133 static void test_acquire_data_fd(void) {
135 test_acquire_data_fd_one(0);
136 test_acquire_data_fd_one(ACQUIRE_NO_DEV_NULL
);
137 test_acquire_data_fd_one(ACQUIRE_NO_MEMFD
);
138 test_acquire_data_fd_one(ACQUIRE_NO_DEV_NULL
|ACQUIRE_NO_MEMFD
);
139 test_acquire_data_fd_one(ACQUIRE_NO_PIPE
);
140 test_acquire_data_fd_one(ACQUIRE_NO_DEV_NULL
|ACQUIRE_NO_PIPE
);
141 test_acquire_data_fd_one(ACQUIRE_NO_MEMFD
|ACQUIRE_NO_PIPE
);
142 test_acquire_data_fd_one(ACQUIRE_NO_DEV_NULL
|ACQUIRE_NO_MEMFD
|ACQUIRE_NO_PIPE
);
143 test_acquire_data_fd_one(ACQUIRE_NO_DEV_NULL
|ACQUIRE_NO_MEMFD
|ACQUIRE_NO_PIPE
|ACQUIRE_NO_TMPFILE
);
146 static void test_fd_move_above_stdio(void) {
147 int original_stdin
, new_fd
;
149 original_stdin
= fcntl(0, F_DUPFD
, 3);
150 assert_se(original_stdin
>= 3);
151 assert_se(close_nointr(0) != EBADF
);
153 new_fd
= open("/dev/null", O_RDONLY
);
154 assert_se(new_fd
== 0);
156 new_fd
= fd_move_above_stdio(new_fd
);
157 assert_se(new_fd
>= 3);
159 assert_se(dup(original_stdin
) == 0);
160 assert_se(close_nointr(original_stdin
) != EBADF
);
161 assert_se(close_nointr(new_fd
) != EBADF
);
164 static void test_rearrange_stdio(void) {
168 r
= safe_fork("rearrange", FORK_WAIT
|FORK_LOG
, &pid
);
172 _cleanup_free_
char *path
= NULL
;
177 safe_close(STDERR_FILENO
); /* Let's close an fd < 2, to make it more interesting */
179 assert_se(rearrange_stdio(-1, -1, -1) >= 0);
181 assert_se(fd_get_path(STDIN_FILENO
, &path
) >= 0);
182 assert_se(path_equal(path
, "/dev/null"));
185 assert_se(fd_get_path(STDOUT_FILENO
, &path
) >= 0);
186 assert_se(path_equal(path
, "/dev/null"));
189 assert_se(fd_get_path(STDOUT_FILENO
, &path
) >= 0);
190 assert_se(path_equal(path
, "/dev/null"));
193 safe_close(STDIN_FILENO
);
194 safe_close(STDOUT_FILENO
);
195 safe_close(STDERR_FILENO
);
199 assert_se(pipe(pair
) >= 0);
200 assert_se(pair
[0] == 0);
201 assert_se(pair
[1] == 1);
202 assert_se(fd_move_above_stdio(0) == 3);
204 assert_se(open("/dev/full", O_WRONLY
|O_CLOEXEC
) == 0);
205 assert_se(acquire_data_fd("foobar", 6, 0) == 2);
207 assert_se(rearrange_stdio(2, 0, 1) >= 0);
209 assert_se(write(1, "x", 1) < 0 && errno
== ENOSPC
);
210 assert_se(write(2, "z", 1) == 1);
211 assert_se(read(3, buffer
, sizeof(buffer
)) == 1);
212 assert_se(buffer
[0] == 'z');
213 assert_se(read(0, buffer
, sizeof(buffer
)) == 6);
214 assert_se(memcmp(buffer
, "foobar", 6) == 0);
216 assert_se(rearrange_stdio(-1, 1, 2) >= 0);
217 assert_se(write(1, "a", 1) < 0 && errno
== ENOSPC
);
218 assert_se(write(2, "y", 1) == 1);
219 assert_se(read(3, buffer
, sizeof(buffer
)) == 1);
220 assert_se(buffer
[0] == 'y');
222 assert_se(fd_get_path(0, &path
) >= 0);
223 assert_se(path_equal(path
, "/dev/null"));
230 static void assert_equal_fd(int fd1
, int fd2
) {
233 uint8_t a
[4096], b
[4096];
236 x
= read(fd1
, a
, sizeof(a
));
239 y
= read(fd2
, b
, sizeof(b
));
247 assert_se(memcmp(a
, b
, x
) == 0);
251 static void test_fd_duplicate_data_fd(void) {
252 _cleanup_close_
int fd1
= -1, fd2
= -1;
253 _cleanup_(close_pairp
) int sfd
[2] = { -1, -1 };
254 _cleanup_(sigkill_waitp
) pid_t pid
= -1;
258 fd1
= open("/etc/fstab", O_RDONLY
|O_CLOEXEC
);
261 fd2
= fd_duplicate_data_fd(fd1
);
264 assert_se(lseek(fd1
, 0, SEEK_SET
) == 0);
265 assert_equal_fd(fd1
, fd2
);
268 fd1
= safe_close(fd1
);
269 fd2
= safe_close(fd2
);
271 fd1
= acquire_data_fd("hallo", 6, 0);
274 fd2
= fd_duplicate_data_fd(fd1
);
278 fd1
= acquire_data_fd("hallo", 6, 0);
281 assert_equal_fd(fd1
, fd2
);
283 fd1
= safe_close(fd1
);
284 fd2
= safe_close(fd2
);
286 assert_se(socketpair(AF_UNIX
, SOCK_STREAM
|SOCK_CLOEXEC
, 0, sfd
) >= 0);
288 r
= safe_fork("(sd-pipe)", FORK_RESET_SIGNALS
|FORK_DEATHSIG
|FORK_LOG
, &pid
);
294 sfd
[0] = safe_close(sfd
[0]);
296 for (i
= 0; i
< 1536*1024 / sizeof(uint64_t); i
++)
297 assert_se(write(sfd
[1], &i
, sizeof(i
)) == sizeof(i
));
299 sfd
[1] = safe_close(sfd
[1]);
304 sfd
[1] = safe_close(sfd
[1]);
306 fd2
= fd_duplicate_data_fd(sfd
[0]);
309 for (i
= 0; i
< 1536*1024 / sizeof(uint64_t); i
++) {
310 assert_se(read(fd2
, &j
, sizeof(j
)) == sizeof(j
));
314 assert_se(read(fd2
, &j
, sizeof(j
)) == 0);
317 static void test_read_nr_open(void) {
318 log_info("nr-open: %i", read_nr_open());
321 static size_t validate_fds(
328 /* Validates that fds in the specified array are one of the following three:
330 * 1. < 0 (test is skipped) or
331 * 2. opened (if 'opened' param is true) or
332 * 3. closed (if 'opened' param is false)
335 for (size_t i
= 0; i
< n_fds
; i
++) {
340 assert_se(fcntl(fds
[i
], F_GETFD
) >= 0);
342 assert_se(fcntl(fds
[i
], F_GETFD
) < 0 && errno
== EBADF
);
347 return c
; /* Return number of fds >= 0 in the array */
350 static void test_close_all_fds(void) {
351 _cleanup_free_
int *fds
= NULL
, *keep
= NULL
;
353 size_t n_fds
, n_keep
;
355 log_info("/* %s */", __func__
);
357 rlimit_nofile_bump(-1);
359 assert_se(getrlimit(RLIMIT_NOFILE
, &rl
) >= 0);
360 assert_se(rl
.rlim_cur
> 10);
362 /* Try to use 5000 fds, but when we can't bump the rlimit to make that happen use the whole limit minus 10 */
363 n_fds
= MIN((rl
.rlim_cur
& ~1U) - 10U, 5000U);
364 assert_se((n_fds
& 1U) == 0U); /* make sure even number of fds */
366 /* Allocate the determined number of fds, always two at a time */
367 assert_se(fds
= new(int, n_fds
));
368 for (size_t i
= 0; i
< n_fds
; i
+= 2)
369 assert_se(pipe2(fds
+ i
, O_CLOEXEC
) >= 0);
371 /* Validate this worked */
372 assert_se(validate_fds(true, fds
, n_fds
) == n_fds
);
374 /* Randomized number of fds to keep, but at most every second */
375 n_keep
= (random_u64() % (n_fds
/ 2));
377 /* Now randomly select a number of fds from the array above to keep */
378 assert_se(keep
= new(int, n_keep
));
379 for (size_t k
= 0; k
< n_keep
; k
++) {
383 p
= random_u64() % n_fds
;
385 keep
[k
] = TAKE_FD(fds
[p
]);
391 /* Check that all fds from both arrays are still open, and test how many in each are >= 0 */
392 assert_se(validate_fds(true, fds
, n_fds
) == n_fds
- n_keep
);
393 assert_se(validate_fds(true, keep
, n_keep
) == n_keep
);
395 /* Close logging fd first, so that we don't confuse it by closing its fd */
397 log_set_open_when_needed(true);
399 /* Close all but the ones to keep */
400 assert_se(close_all_fds(keep
, n_keep
) >= 0);
402 assert_se(validate_fds(false, fds
, n_fds
) == n_fds
- n_keep
);
403 assert_se(validate_fds(true, keep
, n_keep
) == n_keep
);
405 /* Close everything else too! */
406 assert_se(close_all_fds(NULL
, 0) >= 0);
408 assert_se(validate_fds(false, fds
, n_fds
) == n_fds
- n_keep
);
409 assert_se(validate_fds(false, keep
, n_keep
) == n_keep
);
411 log_set_open_when_needed(false);
415 int main(int argc
, char *argv
[]) {
417 test_setup_logging(LOG_DEBUG
);
422 test_open_serialization_fd();
423 test_acquire_data_fd();
424 test_fd_move_above_stdio();
425 test_rearrange_stdio();
426 test_fd_duplicate_data_fd();
428 test_close_all_fds();