]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/test/test-mount-util.c
use FOREACH_ELEMENT
[thirdparty/systemd.git] / src / test / test-mount-util.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
83555251
LP
2
3#include <sys/mount.h>
10cdbb83 4#include <sys/statvfs.h>
83555251 5
c2a986d5 6#include "alloc-util.h"
c75370cc 7#include "capability-util.h"
10cdbb83
LP
8#include "fd-util.h"
9#include "fileio.h"
9c653536 10#include "fs-util.h"
4e9ef660 11#include "libmount-util.h"
f63a2c48 12#include "missing_magic.h"
51bb6a10 13#include "missing_mount.h"
9c653536 14#include "mkdir.h"
83555251 15#include "mount-util.h"
61ef3051 16#include "mountpoint-util.h"
10cdbb83
LP
17#include "namespace-util.h"
18#include "path-util.h"
19#include "process-util.h"
ea0f3289 20#include "random-util.h"
10cdbb83 21#include "rm-rf.h"
f63a2c48 22#include "stat-util.h"
83555251 23#include "string-util.h"
10cdbb83 24#include "strv.h"
6d7c4033 25#include "tests.h"
10cdbb83 26#include "tmpfile-util.h"
83555251 27
4f7452a8 28TEST(mount_option_mangle) {
f27b437b
YW
29 char *opts = NULL;
30 unsigned long f;
31
32 assert_se(mount_option_mangle(NULL, MS_RDONLY|MS_NOSUID, &f, &opts) == 0);
33 assert_se(f == (MS_RDONLY|MS_NOSUID));
5152b845 34 ASSERT_NULL(opts);
f27b437b
YW
35
36 assert_se(mount_option_mangle("", MS_RDONLY|MS_NOSUID, &f, &opts) == 0);
37 assert_se(f == (MS_RDONLY|MS_NOSUID));
5152b845 38 ASSERT_NULL(opts);
f27b437b
YW
39
40 assert_se(mount_option_mangle("ro,nosuid,nodev,noexec", 0, &f, &opts) == 0);
41 assert_se(f == (MS_RDONLY|MS_NOSUID|MS_NODEV|MS_NOEXEC));
5152b845 42 ASSERT_NULL(opts);
f27b437b 43
9f563f27 44 assert_se(mount_option_mangle("ro,nosuid,nodev,noexec,mode=0755", 0, &f, &opts) == 0);
f27b437b 45 assert_se(f == (MS_RDONLY|MS_NOSUID|MS_NODEV|MS_NOEXEC));
c79e88b3 46 ASSERT_STREQ(opts, "mode=0755");
f27b437b
YW
47 opts = mfree(opts);
48
9f563f27 49 assert_se(mount_option_mangle("rw,nosuid,foo,hogehoge,nodev,mode=0755", 0, &f, &opts) == 0);
f27b437b 50 assert_se(f == (MS_NOSUID|MS_NODEV));
c79e88b3 51 ASSERT_STREQ(opts, "foo,hogehoge,mode=0755");
f27b437b
YW
52 opts = mfree(opts);
53
54 assert_se(mount_option_mangle("rw,nosuid,nodev,noexec,relatime,net_cls,net_prio", MS_RDONLY, &f, &opts) == 0);
55 assert_se(f == (MS_NOSUID|MS_NODEV|MS_NOEXEC|MS_RELATIME));
c79e88b3 56 ASSERT_STREQ(opts, "net_cls,net_prio");
f27b437b
YW
57 opts = mfree(opts);
58
9f563f27 59 assert_se(mount_option_mangle("rw,nosuid,nodev,relatime,size=1630748k,mode=0700,uid=1000,gid=1000", MS_RDONLY, &f, &opts) == 0);
f27b437b 60 assert_se(f == (MS_NOSUID|MS_NODEV|MS_RELATIME));
c79e88b3 61 ASSERT_STREQ(opts, "size=1630748k,mode=0700,uid=1000,gid=1000");
f27b437b
YW
62 opts = mfree(opts);
63
9f563f27 64 assert_se(mount_option_mangle("size=1630748k,rw,gid=1000,,,nodev,relatime,,mode=0700,nosuid,uid=1000", MS_RDONLY, &f, &opts) == 0);
f27b437b 65 assert_se(f == (MS_NOSUID|MS_NODEV|MS_RELATIME));
c79e88b3 66 ASSERT_STREQ(opts, "size=1630748k,gid=1000,mode=0700,uid=1000");
f27b437b
YW
67 opts = mfree(opts);
68
9f563f27 69 assert_se(mount_option_mangle("rw,exec,size=8143984k,nr_inodes=2035996,mode=0755", MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV, &f, &opts) == 0);
f27b437b 70 assert_se(f == (MS_NOSUID|MS_NODEV));
c79e88b3 71 ASSERT_STREQ(opts, "size=8143984k,nr_inodes=2035996,mode=0755");
f27b437b
YW
72 opts = mfree(opts);
73
74 assert_se(mount_option_mangle("rw,relatime,fmask=0022,,,dmask=0022", MS_RDONLY, &f, &opts) == 0);
75 assert_se(f == MS_RELATIME);
c79e88b3 76 ASSERT_STREQ(opts, "fmask=0022,dmask=0022");
f27b437b
YW
77 opts = mfree(opts);
78
79 assert_se(mount_option_mangle("rw,relatime,fmask=0022,dmask=0022,\"hogehoge", MS_RDONLY, &f, &opts) < 0);
9b23679e 80
9f563f27 81 assert_se(mount_option_mangle("mode=01777,size=10%,nr_inodes=400k,uid=496107520,gid=496107520,context=\"system_u:object_r:svirt_sandbox_file_t:s0:c0,c1\"", 0, &f, &opts) == 0);
9b23679e 82 assert_se(f == 0);
c79e88b3 83 ASSERT_STREQ(opts, "mode=01777,size=10%,nr_inodes=400k,uid=496107520,gid=496107520,context=\"system_u:object_r:svirt_sandbox_file_t:s0:c0,c1\"");
9b23679e 84 opts = mfree(opts);
f27b437b
YW
85}
86
51bb6a10
ZJS
87static void test_mount_flags_to_string_one(unsigned long flags, const char *expected) {
88 _cleanup_free_ char *x = NULL;
89 int r;
90
91 r = mount_flags_to_string(flags, &x);
92 log_info("flags: %#lX → %d/\"%s\"", flags, r, strnull(x));
93 assert_se(r >= 0);
c79e88b3 94 ASSERT_STREQ(x, expected);
51bb6a10
ZJS
95}
96
4f7452a8 97TEST(mount_flags_to_string) {
51bb6a10
ZJS
98 test_mount_flags_to_string_one(0, "0");
99 test_mount_flags_to_string_one(MS_RDONLY, "MS_RDONLY");
100 test_mount_flags_to_string_one(MS_NOSUID, "MS_NOSUID");
101 test_mount_flags_to_string_one(MS_NODEV, "MS_NODEV");
102 test_mount_flags_to_string_one(MS_NOEXEC, "MS_NOEXEC");
103 test_mount_flags_to_string_one(MS_SYNCHRONOUS, "MS_SYNCHRONOUS");
104 test_mount_flags_to_string_one(MS_REMOUNT, "MS_REMOUNT");
105 test_mount_flags_to_string_one(MS_MANDLOCK, "MS_MANDLOCK");
106 test_mount_flags_to_string_one(MS_DIRSYNC, "MS_DIRSYNC");
107 test_mount_flags_to_string_one(MS_NOSYMFOLLOW, "MS_NOSYMFOLLOW");
108 test_mount_flags_to_string_one(MS_NOATIME, "MS_NOATIME");
109 test_mount_flags_to_string_one(MS_NODIRATIME, "MS_NODIRATIME");
110 test_mount_flags_to_string_one(MS_BIND, "MS_BIND");
111 test_mount_flags_to_string_one(MS_MOVE, "MS_MOVE");
112 test_mount_flags_to_string_one(MS_REC, "MS_REC");
113 test_mount_flags_to_string_one(MS_SILENT, "MS_SILENT");
114 test_mount_flags_to_string_one(MS_POSIXACL, "MS_POSIXACL");
115 test_mount_flags_to_string_one(MS_UNBINDABLE, "MS_UNBINDABLE");
116 test_mount_flags_to_string_one(MS_PRIVATE, "MS_PRIVATE");
117 test_mount_flags_to_string_one(MS_SLAVE, "MS_SLAVE");
118 test_mount_flags_to_string_one(MS_SHARED, "MS_SHARED");
119 test_mount_flags_to_string_one(MS_RELATIME, "MS_RELATIME");
120 test_mount_flags_to_string_one(MS_KERNMOUNT, "MS_KERNMOUNT");
121 test_mount_flags_to_string_one(MS_I_VERSION, "MS_I_VERSION");
122 test_mount_flags_to_string_one(MS_STRICTATIME, "MS_STRICTATIME");
123 test_mount_flags_to_string_one(MS_LAZYTIME, "MS_LAZYTIME");
124 test_mount_flags_to_string_one(MS_LAZYTIME|MS_STRICTATIME, "MS_STRICTATIME|MS_LAZYTIME");
125 test_mount_flags_to_string_one(UINT_MAX,
126 "MS_RDONLY|MS_NOSUID|MS_NODEV|MS_NOEXEC|MS_SYNCHRONOUS|MS_REMOUNT|"
127 "MS_MANDLOCK|MS_DIRSYNC|MS_NOSYMFOLLOW|MS_NOATIME|MS_NODIRATIME|"
128 "MS_BIND|MS_MOVE|MS_REC|MS_SILENT|MS_POSIXACL|MS_UNBINDABLE|"
129 "MS_PRIVATE|MS_SLAVE|MS_SHARED|MS_RELATIME|MS_KERNMOUNT|"
130 "MS_I_VERSION|MS_STRICTATIME|MS_LAZYTIME|fc000200");
131}
132
4f7452a8 133TEST(bind_remount_recursive) {
10cdbb83
LP
134 _cleanup_(rm_rf_physical_and_freep) char *tmp = NULL;
135 _cleanup_free_ char *subdir = NULL;
10cdbb83 136
c75370cc
LP
137 if (geteuid() != 0 || have_effective_cap(CAP_SYS_ADMIN) <= 0) {
138 (void) log_tests_skipped("not running privileged");
10cdbb83
LP
139 return;
140 }
141
142 assert_se(mkdtemp_malloc("/tmp/XXXXXX", &tmp) >= 0);
143 subdir = path_join(tmp, "subdir");
144 assert_se(subdir);
145 assert_se(mkdir(subdir, 0755) >= 0);
146
147 FOREACH_STRING(p, "/usr", "/sys", "/", tmp) {
148 pid_t pid;
149
150 pid = fork();
151 assert_se(pid >= 0);
152
153 if (pid == 0) {
154 struct statvfs svfs;
155 /* child */
156 assert_se(detach_mount_namespace() >= 0);
157
158 /* Check that the subdir is writable (it must be because it's in /tmp) */
159 assert_se(statvfs(subdir, &svfs) >= 0);
160 assert_se(!FLAGS_SET(svfs.f_flag, ST_RDONLY));
161
162 /* Make the subdir a bind mount */
163 assert_se(mount_nofollow(subdir, subdir, NULL, MS_BIND|MS_REC, NULL) >= 0);
164
165 /* Ensure it's still writable */
166 assert_se(statvfs(subdir, &svfs) >= 0);
167 assert_se(!FLAGS_SET(svfs.f_flag, ST_RDONLY));
168
169 /* Now mark the path we currently run for read-only */
874052c5 170 assert_se(bind_remount_recursive(p, MS_RDONLY, MS_RDONLY, path_equal(p, "/sys") ? STRV_MAKE("/sys/kernel") : NULL) >= 0);
10cdbb83
LP
171
172 /* Ensure that this worked on the top-level */
173 assert_se(statvfs(p, &svfs) >= 0);
174 assert_se(FLAGS_SET(svfs.f_flag, ST_RDONLY));
175
176 /* And ensure this had an effect on the subdir exactly if we are talking about a path above the subdir */
177 assert_se(statvfs(subdir, &svfs) >= 0);
178 assert_se(FLAGS_SET(svfs.f_flag, ST_RDONLY) == !!path_startswith(subdir, p));
179
180 _exit(EXIT_SUCCESS);
181 }
182
183 assert_se(wait_for_terminate_and_check("test-remount-rec", pid, WAIT_LOG) == EXIT_SUCCESS);
184 }
185}
186
4f7452a8 187TEST(bind_remount_one) {
67d22a36
LP
188 pid_t pid;
189
c75370cc
LP
190 if (geteuid() != 0 || have_effective_cap(CAP_SYS_ADMIN) <= 0) {
191 (void) log_tests_skipped("not running privileged");
67d22a36
LP
192 return;
193 }
194
195 pid = fork();
196 assert_se(pid >= 0);
197
198 if (pid == 0) {
199 /* child */
200
201 _cleanup_fclose_ FILE *proc_self_mountinfo = NULL;
202
203 assert_se(detach_mount_namespace() >= 0);
204
205 assert_se(fopen_unlocked("/proc/self/mountinfo", "re", &proc_self_mountinfo) >= 0);
206
207 assert_se(bind_remount_one_with_mountinfo("/run", MS_RDONLY, MS_RDONLY, proc_self_mountinfo) >= 0);
4f5644db 208 assert_se(bind_remount_one_with_mountinfo("/run", MS_NOEXEC, MS_RDONLY|MS_NOEXEC, proc_self_mountinfo) >= 0);
67d22a36
LP
209 assert_se(bind_remount_one_with_mountinfo("/proc/idontexist", MS_RDONLY, MS_RDONLY, proc_self_mountinfo) == -ENOENT);
210 assert_se(bind_remount_one_with_mountinfo("/proc/self", MS_RDONLY, MS_RDONLY, proc_self_mountinfo) == -EINVAL);
211 assert_se(bind_remount_one_with_mountinfo("/", MS_RDONLY, MS_RDONLY, proc_self_mountinfo) >= 0);
212
213 _exit(EXIT_SUCCESS);
214 }
215
1927bcdc
KN
216 assert_se(wait_for_terminate_and_check("test-remount-one-with-mountinfo", pid, WAIT_LOG) == EXIT_SUCCESS);
217
218 pid = fork();
219 assert_se(pid >= 0);
220
221 if (pid == 0) {
222 /* child */
223
224 assert_se(detach_mount_namespace() >= 0);
225
226 assert_se(bind_remount_one("/run", MS_RDONLY, MS_RDONLY) >= 0);
227 assert_se(bind_remount_one("/run", MS_NOEXEC, MS_RDONLY|MS_NOEXEC) >= 0);
228 assert_se(bind_remount_one("/proc/idontexist", MS_RDONLY, MS_RDONLY) == -ENOENT);
229 assert_se(bind_remount_one("/proc/self", MS_RDONLY, MS_RDONLY) == -EINVAL);
230 assert_se(bind_remount_one("/", MS_RDONLY, MS_RDONLY) >= 0);
231
232 _exit(EXIT_SUCCESS);
233 }
234
67d22a36
LP
235 assert_se(wait_for_terminate_and_check("test-remount-one", pid, WAIT_LOG) == EXIT_SUCCESS);
236}
237
4f7452a8 238TEST(make_mount_point_inode) {
9c653536
ZJS
239 _cleanup_(rm_rf_physical_and_freep) char *d = NULL;
240 const char *src_file, *src_dir, *dst_file, *dst_dir;
241 struct stat st;
242
9c653536
ZJS
243 assert_se(mkdtemp_malloc(NULL, &d) >= 0);
244
245 src_file = strjoina(d, "/src/file");
246 src_dir = strjoina(d, "/src/dir");
247 dst_file = strjoina(d, "/dst/file");
248 dst_dir = strjoina(d, "/dst/dir");
249
250 assert_se(mkdir_p(src_dir, 0755) >= 0);
251 assert_se(mkdir_parents(dst_file, 0755) >= 0);
252 assert_se(touch(src_file) >= 0);
253
254 assert_se(make_mount_point_inode_from_path(src_file, dst_file, 0755) >= 0);
255 assert_se(make_mount_point_inode_from_path(src_dir, dst_dir, 0755) >= 0);
256
257 assert_se(stat(dst_dir, &st) == 0);
258 assert_se(S_ISDIR(st.st_mode));
259 assert_se(stat(dst_file, &st) == 0);
260 assert_se(S_ISREG(st.st_mode));
261 assert_se(!(S_IXUSR & st.st_mode));
262 assert_se(!(S_IXGRP & st.st_mode));
263 assert_se(!(S_IXOTH & st.st_mode));
264
265 assert_se(unlink(dst_file) == 0);
266 assert_se(rmdir(dst_dir) == 0);
267
268 assert_se(stat(src_file, &st) == 0);
269 assert_se(make_mount_point_inode_from_stat(&st, dst_file, 0755) >= 0);
270 assert_se(stat(src_dir, &st) == 0);
271 assert_se(make_mount_point_inode_from_stat(&st, dst_dir, 0755) >= 0);
272
273 assert_se(stat(dst_dir, &st) == 0);
274 assert_se(S_ISDIR(st.st_mode));
275 assert_se(stat(dst_file, &st) == 0);
276 assert_se(S_ISREG(st.st_mode));
277 assert_se(!(S_IXUSR & st.st_mode));
278 assert_se(!(S_IXGRP & st.st_mode));
279 assert_se(!(S_IXOTH & st.st_mode));
280}
281
ea0f3289
LP
282TEST(make_mount_switch_root) {
283 _cleanup_(rm_rf_physical_and_freep) char *t = NULL;
284 _cleanup_free_ char *s = NULL;
285 int r;
286
287 if (geteuid() != 0 || have_effective_cap(CAP_SYS_ADMIN) <= 0) {
288 (void) log_tests_skipped("not running privileged");
289 return;
290 }
291
292 assert_se(mkdtemp_malloc(NULL, &t) >= 0);
293
294 assert_se(asprintf(&s, "%s/somerandomname%" PRIu64, t, random_u64()) >= 0);
295 assert_se(s);
296 assert_se(touch(s) >= 0);
297
bb59b922
LP
298 struct {
299 const char *path;
300 bool force_ms_move;
301 } table[] = {
302 { t, false },
303 { t, true },
304 { "/", false },
305 { "/", true },
306 };
307
85471164 308 FOREACH_ELEMENT(i, table) {
4e9ef660 309 r = safe_fork("(switch-root)",
ea0f3289
LP
310 FORK_RESET_SIGNALS |
311 FORK_CLOSE_ALL_FDS |
e9ccae31 312 FORK_DEATHSIG_SIGTERM |
ea0f3289
LP
313 FORK_WAIT |
314 FORK_REOPEN_LOG |
315 FORK_LOG |
316 FORK_NEW_MOUNTNS |
317 FORK_MOUNTNS_SLAVE,
318 NULL);
319 assert_se(r >= 0);
320
321 if (r == 0) {
bb59b922
LP
322 assert_se(make_mount_point(i->path) >= 0);
323 assert_se(mount_switch_root_full(i->path, /* mount_propagation_flag= */ 0, i->force_ms_move) >= 0);
324
325 if (!path_equal(i->path, "/")) {
326 assert_se(access(ASSERT_PTR(strrchr(s, '/')), F_OK) >= 0); /* absolute */
327 assert_se(access(ASSERT_PTR(strrchr(s, '/')) + 1, F_OK) >= 0); /* relative */
328 assert_se(access(s, F_OK) < 0 && errno == ENOENT); /* doesn't exist in our new environment */
329 }
ea0f3289
LP
330
331 _exit(EXIT_SUCCESS);
332 }
333 }
334}
335
4e9ef660
LP
336TEST(umount_recursive) {
337 static const struct {
338 const char *prefix;
339 const char * const keep[3];
340 } test_table[] = {
341 {
342 .prefix = NULL,
343 .keep = {},
344 },
345 {
346 .prefix = "/run",
347 .keep = {},
348 },
349 {
350 .prefix = NULL,
351 .keep = { "/dev/shm", NULL },
352 },
353 {
354 .prefix = "/dev",
355 .keep = { "/dev/pts", "/dev/shm", NULL },
356 },
357 };
358
359 int r;
360
85471164 361 FOREACH_ELEMENT(t, test_table) {
4e9ef660
LP
362
363 r = safe_fork("(umount-rec)",
364 FORK_RESET_SIGNALS |
365 FORK_CLOSE_ALL_FDS |
e9ccae31 366 FORK_DEATHSIG_SIGTERM |
4e9ef660
LP
367 FORK_WAIT |
368 FORK_REOPEN_LOG |
369 FORK_LOG |
370 FORK_NEW_MOUNTNS |
371 FORK_MOUNTNS_SLAVE,
372 NULL);
373
13d84288
ZJS
374 if (ERRNO_IS_NEG_PRIVILEGE(r))
375 return (void) log_notice("Skipping umount_recursive() test, lacking privileges");
4e9ef660
LP
376
377 assert_se(r >= 0);
378 if (r == 0) { /* child */
379 _cleanup_(mnt_free_tablep) struct libmnt_table *table = NULL;
380 _cleanup_(mnt_free_iterp) struct libmnt_iter *iter = NULL;
381 _cleanup_fclose_ FILE *f = NULL;
382 _cleanup_free_ char *k = NULL;
383
384 /* Open /p/s/m file before we unmount everything (which might include /proc/) */
385 f = fopen("/proc/self/mountinfo", "re");
386 if (!f) {
9a27ef09 387 log_error_errno(errno, "Failed to open /proc/self/mountinfo: %m");
4e9ef660
LP
388 _exit(EXIT_FAILURE);
389 }
390
391 assert_se(k = strv_join((char**) t->keep, " "));
392 log_info("detaching just %s (keep: %s)", strna(t->prefix), strna(empty_to_null(k)));
393
394 assert_se(umount_recursive_full(t->prefix, MNT_DETACH, (char**) t->keep) >= 0);
395
396 r = libmount_parse("/proc/self/mountinfo", f, &table, &iter);
397 if (r < 0) {
398 log_error_errno(r, "Failed to parse /proc/self/mountinfo: %m");
399 _exit(EXIT_FAILURE);
400 }
401
402 for (;;) {
403 struct libmnt_fs *fs;
404
405 r = mnt_table_next_fs(table, iter, &fs);
406 if (r == 1)
407 break;
408 if (r < 0) {
409 log_error_errno(r, "Failed to get next entry from /proc/self/mountinfo: %m");
410 _exit(EXIT_FAILURE);
411 }
412
413 log_debug("left after complete umount: %s", mnt_fs_get_target(fs));
414 }
415
416 _exit(EXIT_SUCCESS);
417 }
418 }
419}
420
f9ad896e
LP
421TEST(fd_make_mount_point) {
422 _cleanup_(rm_rf_physical_and_freep) char *t = NULL;
423 _cleanup_free_ char *s = NULL;
424 int r;
425
426 if (geteuid() != 0 || have_effective_cap(CAP_SYS_ADMIN) <= 0) {
427 (void) log_tests_skipped("not running privileged");
428 return;
429 }
430
431 assert_se(mkdtemp_malloc(NULL, &t) >= 0);
432
433 assert_se(asprintf(&s, "%s/somerandomname%" PRIu64, t, random_u64()) >= 0);
434 assert_se(s);
435 assert_se(mkdir(s, 0700) >= 0);
436
437 r = safe_fork("(make_mount-point)",
438 FORK_RESET_SIGNALS |
439 FORK_CLOSE_ALL_FDS |
e9ccae31 440 FORK_DEATHSIG_SIGTERM |
f9ad896e
LP
441 FORK_WAIT |
442 FORK_REOPEN_LOG |
443 FORK_LOG |
444 FORK_NEW_MOUNTNS |
445 FORK_MOUNTNS_SLAVE,
446 NULL);
447 assert_se(r >= 0);
448
449 if (r == 0) {
450 _cleanup_close_ int fd = -EBADF, fd2 = -EBADF;
451
452 fd = open(s, O_PATH|O_CLOEXEC);
453 assert_se(fd >= 0);
454
455 assert_se(fd_is_mount_point(fd, NULL, AT_SYMLINK_FOLLOW) == 0);
456
457 assert_se(fd_make_mount_point(fd) > 0);
458
459 /* Reopen the inode so that we end up on the new mount */
460 fd2 = open(s, O_PATH|O_CLOEXEC);
461
462 assert_se(fd_is_mount_point(fd2, NULL, AT_SYMLINK_FOLLOW) > 0);
463
464 assert_se(fd_make_mount_point(fd2) == 0);
465
466 _exit(EXIT_SUCCESS);
467 }
468}
469
1b618bf1
LP
470TEST(bind_mount_submounts) {
471 _cleanup_(rmdir_and_freep) char *a = NULL, *b = NULL;
472 _cleanup_free_ char *x = NULL;
473 int r;
474
475 assert_se(mkdtemp_malloc(NULL, &a) >= 0);
476 r = mount_nofollow_verbose(LOG_INFO, "tmpfs", a, "tmpfs", 0, NULL);
13d84288
ZJS
477 if (ERRNO_IS_NEG_PRIVILEGE(r))
478 return (void) log_tests_skipped("Skipping bind_mount_submounts() test, lacking privileges");
479
1b618bf1
LP
480 assert_se(r >= 0);
481
482 assert_se(x = path_join(a, "foo"));
483 assert_se(touch(x) >= 0);
484 free(x);
485
486 assert_se(x = path_join(a, "x"));
487 assert_se(mkdir(x, 0755) >= 0);
488 assert_se(mount_nofollow_verbose(LOG_INFO, "tmpfs", x, "tmpfs", 0, NULL) >= 0);
489 free(x);
490
491 assert_se(x = path_join(a, "x/xx"));
492 assert_se(touch(x) >= 0);
493 free(x);
494
495 assert_se(x = path_join(a, "y"));
496 assert_se(mkdir(x, 0755) >= 0);
497 assert_se(mount_nofollow_verbose(LOG_INFO, "tmpfs", x, "tmpfs", 0, NULL) >= 0);
498 free(x);
499
500 assert_se(x = path_join(a, "y/yy"));
501 assert_se(touch(x) >= 0);
502 free(x);
503
504 assert_se(mkdtemp_malloc(NULL, &b) >= 0);
505 assert_se(mount_nofollow_verbose(LOG_INFO, "tmpfs", b, "tmpfs", 0, NULL) >= 0);
506
507 assert_se(x = path_join(b, "x"));
508 assert_se(mkdir(x, 0755) >= 0);
509 free(x);
510
511 assert_se(x = path_join(b, "y"));
512 assert_se(mkdir(x, 0755) >= 0);
513 free(x);
514
515 assert_se(bind_mount_submounts(a, b) >= 0);
516
517 assert_se(x = path_join(b, "foo"));
518 assert_se(access(x, F_OK) < 0 && errno == ENOENT);
519 free(x);
520
521 assert_se(x = path_join(b, "x/xx"));
522 assert_se(access(x, F_OK) >= 0);
523 free(x);
524
525 assert_se(x = path_join(b, "y/yy"));
526 assert_se(access(x, F_OK) >= 0);
527 free(x);
528
529 assert_se(x = path_join(b, "x"));
b409aacb 530 assert_se(path_is_mount_point(x) > 0);
1b618bf1
LP
531 free(x);
532
533 assert_se(x = path_join(b, "y"));
b409aacb 534 assert_se(path_is_mount_point(x) > 0);
1b618bf1
LP
535
536 assert_se(umount_recursive(a, 0) >= 0);
537 assert_se(umount_recursive(b, 0) >= 0);
538}
539
2b60ce54 540DEFINE_TEST_MAIN(LOG_DEBUG);