]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/test/test-mount-util.c
e2765d0c912805b0bd4aa518e0a463b8b68dbd3b
1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 Copyright 2016 Lennart Poettering
8 #include "alloc-util.h"
15 #include "mount-util.h"
16 #include "path-util.h"
18 #include "string-util.h"
20 static void test_mount_propagation_flags(const char *name
, int ret
, unsigned long expected
) {
23 assert_se(mount_propagation_flags_from_string(name
, &flags
) == ret
);
28 assert_se(flags
== expected
);
30 c
= mount_propagation_flags_to_string(flags
);
32 assert_se(isempty(c
));
34 assert_se(streq(c
, name
));
38 static void test_mnt_id(void) {
39 _cleanup_fclose_
FILE *f
= NULL
;
46 assert_se(f
= fopen("/proc/self/mountinfo", "re"));
47 assert_se(h
= hashmap_new(&trivial_hash_ops
));
50 _cleanup_free_
char *line
= NULL
, *path
= NULL
;
53 r
= read_line(f
, LONG_LINE_MAX
, &line
);
58 assert_se(sscanf(line
, "%i %*s %*s %*s %ms", &mnt_id
, &path
) == 2);
60 assert_se(hashmap_put(h
, INT_TO_PTR(mnt_id
), path
) >= 0);
64 HASHMAP_FOREACH_KEY(p
, k
, h
, i
) {
65 int mnt_id
= PTR_TO_INT(k
), mnt_id2
;
67 r
= path_get_mnt_id(p
, &mnt_id2
);
69 log_debug_errno(r
, "Failed to get the mnt id of %s: %m\n", p
);
73 log_debug("mnt id of %s is %i\n", p
, mnt_id2
);
75 if (mnt_id
== mnt_id2
)
78 /* The ids don't match? If so, then there are two mounts on the same path, let's check if that's really
80 assert_se(path_equal_ptr(hashmap_get(h
, INT_TO_PTR(mnt_id2
)), p
));
86 static void test_path_is_mount_point(void) {
88 char tmp_dir
[] = "/tmp/test-path-is-mount-point-XXXXXX";
89 _cleanup_free_
char *file1
= NULL
, *file2
= NULL
, *link1
= NULL
, *link2
= NULL
;
90 _cleanup_free_
char *dir1
= NULL
, *dir1file
= NULL
, *dirlink1
= NULL
, *dirlink1file
= NULL
;
91 _cleanup_free_
char *dir2
= NULL
, *dir2file
= NULL
;
93 assert_se(path_is_mount_point("/", NULL
, AT_SYMLINK_FOLLOW
) > 0);
94 assert_se(path_is_mount_point("/", NULL
, 0) > 0);
95 assert_se(path_is_mount_point("//", NULL
, AT_SYMLINK_FOLLOW
) > 0);
96 assert_se(path_is_mount_point("//", NULL
, 0) > 0);
98 assert_se(path_is_mount_point("/proc", NULL
, AT_SYMLINK_FOLLOW
) > 0);
99 assert_se(path_is_mount_point("/proc", NULL
, 0) > 0);
100 assert_se(path_is_mount_point("/proc/", NULL
, AT_SYMLINK_FOLLOW
) > 0);
101 assert_se(path_is_mount_point("/proc/", NULL
, 0) > 0);
103 assert_se(path_is_mount_point("/proc/1", NULL
, AT_SYMLINK_FOLLOW
) == 0);
104 assert_se(path_is_mount_point("/proc/1", NULL
, 0) == 0);
105 assert_se(path_is_mount_point("/proc/1/", NULL
, AT_SYMLINK_FOLLOW
) == 0);
106 assert_se(path_is_mount_point("/proc/1/", NULL
, 0) == 0);
108 assert_se(path_is_mount_point("/sys", NULL
, AT_SYMLINK_FOLLOW
) > 0);
109 assert_se(path_is_mount_point("/sys", NULL
, 0) > 0);
110 assert_se(path_is_mount_point("/sys/", NULL
, AT_SYMLINK_FOLLOW
) > 0);
111 assert_se(path_is_mount_point("/sys/", NULL
, 0) > 0);
113 /* we'll create a hierarchy of different kinds of dir/file/link
116 * <tmp>/file1, <tmp>/file2
117 * <tmp>/link1 -> file1, <tmp>/link2 -> file2
120 * <tmp>/dirlink1 -> dir1
121 * <tmp>/dirlink1file -> dirlink1/file
126 /* file mountpoints */
127 assert_se(mkdtemp(tmp_dir
) != NULL
);
128 file1
= path_join(NULL
, tmp_dir
, "file1");
130 file2
= path_join(NULL
, tmp_dir
, "file2");
132 fd
= open(file1
, O_WRONLY
|O_CREAT
|O_EXCL
|O_CLOEXEC
, 0664);
135 fd
= open(file2
, O_WRONLY
|O_CREAT
|O_EXCL
|O_CLOEXEC
, 0664);
138 link1
= path_join(NULL
, tmp_dir
, "link1");
140 assert_se(symlink("file1", link1
) == 0);
141 link2
= path_join(NULL
, tmp_dir
, "link2");
143 assert_se(symlink("file2", link2
) == 0);
145 assert_se(path_is_mount_point(file1
, NULL
, AT_SYMLINK_FOLLOW
) == 0);
146 assert_se(path_is_mount_point(file1
, NULL
, 0) == 0);
147 assert_se(path_is_mount_point(link1
, NULL
, AT_SYMLINK_FOLLOW
) == 0);
148 assert_se(path_is_mount_point(link1
, NULL
, 0) == 0);
150 /* directory mountpoints */
151 dir1
= path_join(NULL
, tmp_dir
, "dir1");
153 assert_se(mkdir(dir1
, 0755) == 0);
154 dirlink1
= path_join(NULL
, tmp_dir
, "dirlink1");
156 assert_se(symlink("dir1", dirlink1
) == 0);
157 dirlink1file
= path_join(NULL
, tmp_dir
, "dirlink1file");
158 assert_se(dirlink1file
);
159 assert_se(symlink("dirlink1/file", dirlink1file
) == 0);
160 dir2
= path_join(NULL
, tmp_dir
, "dir2");
162 assert_se(mkdir(dir2
, 0755) == 0);
164 assert_se(path_is_mount_point(dir1
, NULL
, AT_SYMLINK_FOLLOW
) == 0);
165 assert_se(path_is_mount_point(dir1
, NULL
, 0) == 0);
166 assert_se(path_is_mount_point(dirlink1
, NULL
, AT_SYMLINK_FOLLOW
) == 0);
167 assert_se(path_is_mount_point(dirlink1
, NULL
, 0) == 0);
169 /* file in subdirectory mountpoints */
170 dir1file
= path_join(NULL
, dir1
, "file");
172 fd
= open(dir1file
, O_WRONLY
|O_CREAT
|O_EXCL
|O_CLOEXEC
, 0664);
176 assert_se(path_is_mount_point(dir1file
, NULL
, AT_SYMLINK_FOLLOW
) == 0);
177 assert_se(path_is_mount_point(dir1file
, NULL
, 0) == 0);
178 assert_se(path_is_mount_point(dirlink1file
, NULL
, AT_SYMLINK_FOLLOW
) == 0);
179 assert_se(path_is_mount_point(dirlink1file
, NULL
, 0) == 0);
181 /* these tests will only work as root */
182 if (mount(file1
, file2
, NULL
, MS_BIND
, NULL
) >= 0) {
183 int rf
, rt
, rdf
, rdt
, rlf
, rlt
, rl1f
, rl1t
;
187 /* capture results in vars, to avoid dangling mounts on failure */
188 log_info("%s: %s", __func__
, file2
);
189 rf
= path_is_mount_point(file2
, NULL
, 0);
190 rt
= path_is_mount_point(file2
, NULL
, AT_SYMLINK_FOLLOW
);
192 file2d
= strjoina(file2
, "/");
193 log_info("%s: %s", __func__
, file2d
);
194 rdf
= path_is_mount_point(file2d
, NULL
, 0);
195 rdt
= path_is_mount_point(file2d
, NULL
, AT_SYMLINK_FOLLOW
);
197 log_info("%s: %s", __func__
, link2
);
198 rlf
= path_is_mount_point(link2
, NULL
, 0);
199 rlt
= path_is_mount_point(link2
, NULL
, AT_SYMLINK_FOLLOW
);
201 assert_se(umount(file2
) == 0);
205 assert_se(rdf
== -ENOTDIR
);
206 assert_se(rdt
== -ENOTDIR
);
211 dir2file
= path_join(NULL
, dir2
, "file");
213 fd
= open(dir2file
, O_WRONLY
|O_CREAT
|O_EXCL
|O_CLOEXEC
, 0664);
217 assert_se(mount(dir2
, dir1
, NULL
, MS_BIND
, NULL
) >= 0);
219 log_info("%s: %s", __func__
, dir1
);
220 rf
= path_is_mount_point(dir1
, NULL
, 0);
221 rt
= path_is_mount_point(dir1
, NULL
, AT_SYMLINK_FOLLOW
);
222 log_info("%s: %s", __func__
, dirlink1
);
223 rlf
= path_is_mount_point(dirlink1
, NULL
, 0);
224 rlt
= path_is_mount_point(dirlink1
, NULL
, AT_SYMLINK_FOLLOW
);
225 log_info("%s: %s", __func__
, dirlink1file
);
226 /* its parent is a mount point, but not /file itself */
227 rl1f
= path_is_mount_point(dirlink1file
, NULL
, 0);
228 rl1t
= path_is_mount_point(dirlink1file
, NULL
, AT_SYMLINK_FOLLOW
);
230 assert_se(umount(dir1
) == 0);
236 assert_se(rl1f
== 0);
237 assert_se(rl1t
== 0);
240 printf("Skipping bind mount file test: %m\n");
242 assert_se(rm_rf(tmp_dir
, REMOVE_ROOT
|REMOVE_PHYSICAL
) == 0);
245 static void test_mount_option_mangle(void) {
249 assert_se(mount_option_mangle(NULL
, MS_RDONLY
|MS_NOSUID
, &f
, &opts
) == 0);
250 assert_se(f
== (MS_RDONLY
|MS_NOSUID
));
251 assert_se(opts
== NULL
);
253 assert_se(mount_option_mangle("", MS_RDONLY
|MS_NOSUID
, &f
, &opts
) == 0);
254 assert_se(f
== (MS_RDONLY
|MS_NOSUID
));
255 assert_se(opts
== NULL
);
257 assert_se(mount_option_mangle("ro,nosuid,nodev,noexec", 0, &f
, &opts
) == 0);
258 assert_se(f
== (MS_RDONLY
|MS_NOSUID
|MS_NODEV
|MS_NOEXEC
));
259 assert_se(opts
== NULL
);
261 assert_se(mount_option_mangle("ro,nosuid,nodev,noexec,mode=755", 0, &f
, &opts
) == 0);
262 assert_se(f
== (MS_RDONLY
|MS_NOSUID
|MS_NODEV
|MS_NOEXEC
));
263 assert_se(streq(opts
, "mode=755"));
266 assert_se(mount_option_mangle("rw,nosuid,foo,hogehoge,nodev,mode=755", 0, &f
, &opts
) == 0);
267 assert_se(f
== (MS_NOSUID
|MS_NODEV
));
268 assert_se(streq(opts
, "foo,hogehoge,mode=755"));
271 assert_se(mount_option_mangle("rw,nosuid,nodev,noexec,relatime,net_cls,net_prio", MS_RDONLY
, &f
, &opts
) == 0);
272 assert_se(f
== (MS_NOSUID
|MS_NODEV
|MS_NOEXEC
|MS_RELATIME
));
273 assert_se(streq(opts
, "net_cls,net_prio"));
276 assert_se(mount_option_mangle("rw,nosuid,nodev,relatime,size=1630748k,mode=700,uid=1000,gid=1000", MS_RDONLY
, &f
, &opts
) == 0);
277 assert_se(f
== (MS_NOSUID
|MS_NODEV
|MS_RELATIME
));
278 assert_se(streq(opts
, "size=1630748k,mode=700,uid=1000,gid=1000"));
281 assert_se(mount_option_mangle("size=1630748k,rw,gid=1000,,,nodev,relatime,,mode=700,nosuid,uid=1000", MS_RDONLY
, &f
, &opts
) == 0);
282 assert_se(f
== (MS_NOSUID
|MS_NODEV
|MS_RELATIME
));
283 assert_se(streq(opts
, "size=1630748k,gid=1000,mode=700,uid=1000"));
286 assert_se(mount_option_mangle("rw,exec,size=8143984k,nr_inodes=2035996,mode=755", MS_RDONLY
|MS_NOSUID
|MS_NOEXEC
|MS_NODEV
, &f
, &opts
) == 0);
287 assert_se(f
== (MS_NOSUID
|MS_NODEV
));
288 assert_se(streq(opts
, "size=8143984k,nr_inodes=2035996,mode=755"));
291 assert_se(mount_option_mangle("rw,relatime,fmask=0022,,,dmask=0022", MS_RDONLY
, &f
, &opts
) == 0);
292 assert_se(f
== MS_RELATIME
);
293 assert_se(streq(opts
, "fmask=0022,dmask=0022"));
296 assert_se(mount_option_mangle("rw,relatime,fmask=0022,dmask=0022,\"hogehoge", MS_RDONLY
, &f
, &opts
) < 0);
299 int main(int argc
, char *argv
[]) {
301 log_set_max_level(LOG_DEBUG
);
303 test_mount_propagation_flags("shared", 0, MS_SHARED
);
304 test_mount_propagation_flags("slave", 0, MS_SLAVE
);
305 test_mount_propagation_flags("private", 0, MS_PRIVATE
);
306 test_mount_propagation_flags(NULL
, 0, 0);
307 test_mount_propagation_flags("", 0, 0);
308 test_mount_propagation_flags("xxxx", -EINVAL
, 0);
309 test_mount_propagation_flags(" ", -EINVAL
, 0);
312 test_path_is_mount_point();
313 test_mount_option_mangle();