]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/test/test-mount-util.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
5 #include "alloc-util.h"
12 #include "mount-util.h"
13 #include "path-util.h"
15 #include "string-util.h"
17 static void test_mount_propagation_flags(const char *name
, int ret
, unsigned long expected
) {
20 assert_se(mount_propagation_flags_from_string(name
, &flags
) == ret
);
25 assert_se(flags
== expected
);
27 c
= mount_propagation_flags_to_string(flags
);
29 assert_se(isempty(c
));
31 assert_se(streq(c
, name
));
35 static void test_mnt_id(void) {
36 _cleanup_fclose_
FILE *f
= NULL
;
43 assert_se(f
= fopen("/proc/self/mountinfo", "re"));
44 assert_se(h
= hashmap_new(&trivial_hash_ops
));
47 _cleanup_free_
char *line
= NULL
, *path
= NULL
;
50 r
= read_line(f
, LONG_LINE_MAX
, &line
);
55 assert_se(sscanf(line
, "%i %*s %*s %*s %ms", &mnt_id
, &path
) == 2);
57 assert_se(hashmap_put(h
, INT_TO_PTR(mnt_id
), path
) >= 0);
61 HASHMAP_FOREACH_KEY(p
, k
, h
, i
) {
62 int mnt_id
= PTR_TO_INT(k
), mnt_id2
;
64 r
= path_get_mnt_id(p
, &mnt_id2
);
66 log_debug_errno(r
, "Failed to get the mnt id of %s: %m\n", p
);
70 log_debug("mnt id of %s is %i\n", p
, mnt_id2
);
72 if (mnt_id
== mnt_id2
)
75 /* The ids don't match? If so, then there are two mounts on the same path, let's check if that's really
77 assert_se(path_equal_ptr(hashmap_get(h
, INT_TO_PTR(mnt_id2
)), p
));
83 static void test_path_is_mount_point(void) {
85 char tmp_dir
[] = "/tmp/test-path-is-mount-point-XXXXXX";
86 _cleanup_free_
char *file1
= NULL
, *file2
= NULL
, *link1
= NULL
, *link2
= NULL
;
87 _cleanup_free_
char *dir1
= NULL
, *dir1file
= NULL
, *dirlink1
= NULL
, *dirlink1file
= NULL
;
88 _cleanup_free_
char *dir2
= NULL
, *dir2file
= NULL
;
90 assert_se(path_is_mount_point("/", NULL
, AT_SYMLINK_FOLLOW
) > 0);
91 assert_se(path_is_mount_point("/", NULL
, 0) > 0);
92 assert_se(path_is_mount_point("//", NULL
, AT_SYMLINK_FOLLOW
) > 0);
93 assert_se(path_is_mount_point("//", NULL
, 0) > 0);
95 assert_se(path_is_mount_point("/proc", NULL
, AT_SYMLINK_FOLLOW
) > 0);
96 assert_se(path_is_mount_point("/proc", NULL
, 0) > 0);
97 assert_se(path_is_mount_point("/proc/", NULL
, AT_SYMLINK_FOLLOW
) > 0);
98 assert_se(path_is_mount_point("/proc/", NULL
, 0) > 0);
100 assert_se(path_is_mount_point("/proc/1", NULL
, AT_SYMLINK_FOLLOW
) == 0);
101 assert_se(path_is_mount_point("/proc/1", NULL
, 0) == 0);
102 assert_se(path_is_mount_point("/proc/1/", NULL
, AT_SYMLINK_FOLLOW
) == 0);
103 assert_se(path_is_mount_point("/proc/1/", NULL
, 0) == 0);
105 assert_se(path_is_mount_point("/sys", NULL
, AT_SYMLINK_FOLLOW
) > 0);
106 assert_se(path_is_mount_point("/sys", NULL
, 0) > 0);
107 assert_se(path_is_mount_point("/sys/", NULL
, AT_SYMLINK_FOLLOW
) > 0);
108 assert_se(path_is_mount_point("/sys/", NULL
, 0) > 0);
110 /* we'll create a hierarchy of different kinds of dir/file/link
113 * <tmp>/file1, <tmp>/file2
114 * <tmp>/link1 -> file1, <tmp>/link2 -> file2
117 * <tmp>/dirlink1 -> dir1
118 * <tmp>/dirlink1file -> dirlink1/file
123 /* file mountpoints */
124 assert_se(mkdtemp(tmp_dir
) != NULL
);
125 file1
= path_join(NULL
, tmp_dir
, "file1");
127 file2
= path_join(NULL
, tmp_dir
, "file2");
129 fd
= open(file1
, O_WRONLY
|O_CREAT
|O_EXCL
|O_CLOEXEC
, 0664);
132 fd
= open(file2
, O_WRONLY
|O_CREAT
|O_EXCL
|O_CLOEXEC
, 0664);
135 link1
= path_join(NULL
, tmp_dir
, "link1");
137 assert_se(symlink("file1", link1
) == 0);
138 link2
= path_join(NULL
, tmp_dir
, "link2");
140 assert_se(symlink("file2", link2
) == 0);
142 assert_se(path_is_mount_point(file1
, NULL
, AT_SYMLINK_FOLLOW
) == 0);
143 assert_se(path_is_mount_point(file1
, NULL
, 0) == 0);
144 assert_se(path_is_mount_point(link1
, NULL
, AT_SYMLINK_FOLLOW
) == 0);
145 assert_se(path_is_mount_point(link1
, NULL
, 0) == 0);
147 /* directory mountpoints */
148 dir1
= path_join(NULL
, tmp_dir
, "dir1");
150 assert_se(mkdir(dir1
, 0755) == 0);
151 dirlink1
= path_join(NULL
, tmp_dir
, "dirlink1");
153 assert_se(symlink("dir1", dirlink1
) == 0);
154 dirlink1file
= path_join(NULL
, tmp_dir
, "dirlink1file");
155 assert_se(dirlink1file
);
156 assert_se(symlink("dirlink1/file", dirlink1file
) == 0);
157 dir2
= path_join(NULL
, tmp_dir
, "dir2");
159 assert_se(mkdir(dir2
, 0755) == 0);
161 assert_se(path_is_mount_point(dir1
, NULL
, AT_SYMLINK_FOLLOW
) == 0);
162 assert_se(path_is_mount_point(dir1
, NULL
, 0) == 0);
163 assert_se(path_is_mount_point(dirlink1
, NULL
, AT_SYMLINK_FOLLOW
) == 0);
164 assert_se(path_is_mount_point(dirlink1
, NULL
, 0) == 0);
166 /* file in subdirectory mountpoints */
167 dir1file
= path_join(NULL
, dir1
, "file");
169 fd
= open(dir1file
, O_WRONLY
|O_CREAT
|O_EXCL
|O_CLOEXEC
, 0664);
173 assert_se(path_is_mount_point(dir1file
, NULL
, AT_SYMLINK_FOLLOW
) == 0);
174 assert_se(path_is_mount_point(dir1file
, NULL
, 0) == 0);
175 assert_se(path_is_mount_point(dirlink1file
, NULL
, AT_SYMLINK_FOLLOW
) == 0);
176 assert_se(path_is_mount_point(dirlink1file
, NULL
, 0) == 0);
178 /* these tests will only work as root */
179 if (mount(file1
, file2
, NULL
, MS_BIND
, NULL
) >= 0) {
180 int rf
, rt
, rdf
, rdt
, rlf
, rlt
, rl1f
, rl1t
;
184 /* capture results in vars, to avoid dangling mounts on failure */
185 log_info("%s: %s", __func__
, file2
);
186 rf
= path_is_mount_point(file2
, NULL
, 0);
187 rt
= path_is_mount_point(file2
, NULL
, AT_SYMLINK_FOLLOW
);
189 file2d
= strjoina(file2
, "/");
190 log_info("%s: %s", __func__
, file2d
);
191 rdf
= path_is_mount_point(file2d
, NULL
, 0);
192 rdt
= path_is_mount_point(file2d
, NULL
, AT_SYMLINK_FOLLOW
);
194 log_info("%s: %s", __func__
, link2
);
195 rlf
= path_is_mount_point(link2
, NULL
, 0);
196 rlt
= path_is_mount_point(link2
, NULL
, AT_SYMLINK_FOLLOW
);
198 assert_se(umount(file2
) == 0);
202 assert_se(rdf
== -ENOTDIR
);
203 assert_se(rdt
== -ENOTDIR
);
208 dir2file
= path_join(NULL
, dir2
, "file");
210 fd
= open(dir2file
, O_WRONLY
|O_CREAT
|O_EXCL
|O_CLOEXEC
, 0664);
214 assert_se(mount(dir2
, dir1
, NULL
, MS_BIND
, NULL
) >= 0);
216 log_info("%s: %s", __func__
, dir1
);
217 rf
= path_is_mount_point(dir1
, NULL
, 0);
218 rt
= path_is_mount_point(dir1
, NULL
, AT_SYMLINK_FOLLOW
);
219 log_info("%s: %s", __func__
, dirlink1
);
220 rlf
= path_is_mount_point(dirlink1
, NULL
, 0);
221 rlt
= path_is_mount_point(dirlink1
, NULL
, AT_SYMLINK_FOLLOW
);
222 log_info("%s: %s", __func__
, dirlink1file
);
223 /* its parent is a mount point, but not /file itself */
224 rl1f
= path_is_mount_point(dirlink1file
, NULL
, 0);
225 rl1t
= path_is_mount_point(dirlink1file
, NULL
, AT_SYMLINK_FOLLOW
);
227 assert_se(umount(dir1
) == 0);
233 assert_se(rl1f
== 0);
234 assert_se(rl1t
== 0);
237 printf("Skipping bind mount file test: %m\n");
239 assert_se(rm_rf(tmp_dir
, REMOVE_ROOT
|REMOVE_PHYSICAL
) == 0);
242 static void test_mount_option_mangle(void) {
246 assert_se(mount_option_mangle(NULL
, MS_RDONLY
|MS_NOSUID
, &f
, &opts
) == 0);
247 assert_se(f
== (MS_RDONLY
|MS_NOSUID
));
248 assert_se(opts
== NULL
);
250 assert_se(mount_option_mangle("", MS_RDONLY
|MS_NOSUID
, &f
, &opts
) == 0);
251 assert_se(f
== (MS_RDONLY
|MS_NOSUID
));
252 assert_se(opts
== NULL
);
254 assert_se(mount_option_mangle("ro,nosuid,nodev,noexec", 0, &f
, &opts
) == 0);
255 assert_se(f
== (MS_RDONLY
|MS_NOSUID
|MS_NODEV
|MS_NOEXEC
));
256 assert_se(opts
== NULL
);
258 assert_se(mount_option_mangle("ro,nosuid,nodev,noexec,mode=755", 0, &f
, &opts
) == 0);
259 assert_se(f
== (MS_RDONLY
|MS_NOSUID
|MS_NODEV
|MS_NOEXEC
));
260 assert_se(streq(opts
, "mode=755"));
263 assert_se(mount_option_mangle("rw,nosuid,foo,hogehoge,nodev,mode=755", 0, &f
, &opts
) == 0);
264 assert_se(f
== (MS_NOSUID
|MS_NODEV
));
265 assert_se(streq(opts
, "foo,hogehoge,mode=755"));
268 assert_se(mount_option_mangle("rw,nosuid,nodev,noexec,relatime,net_cls,net_prio", MS_RDONLY
, &f
, &opts
) == 0);
269 assert_se(f
== (MS_NOSUID
|MS_NODEV
|MS_NOEXEC
|MS_RELATIME
));
270 assert_se(streq(opts
, "net_cls,net_prio"));
273 assert_se(mount_option_mangle("rw,nosuid,nodev,relatime,size=1630748k,mode=700,uid=1000,gid=1000", MS_RDONLY
, &f
, &opts
) == 0);
274 assert_se(f
== (MS_NOSUID
|MS_NODEV
|MS_RELATIME
));
275 assert_se(streq(opts
, "size=1630748k,mode=700,uid=1000,gid=1000"));
278 assert_se(mount_option_mangle("size=1630748k,rw,gid=1000,,,nodev,relatime,,mode=700,nosuid,uid=1000", MS_RDONLY
, &f
, &opts
) == 0);
279 assert_se(f
== (MS_NOSUID
|MS_NODEV
|MS_RELATIME
));
280 assert_se(streq(opts
, "size=1630748k,gid=1000,mode=700,uid=1000"));
283 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);
284 assert_se(f
== (MS_NOSUID
|MS_NODEV
));
285 assert_se(streq(opts
, "size=8143984k,nr_inodes=2035996,mode=755"));
288 assert_se(mount_option_mangle("rw,relatime,fmask=0022,,,dmask=0022", MS_RDONLY
, &f
, &opts
) == 0);
289 assert_se(f
== MS_RELATIME
);
290 assert_se(streq(opts
, "fmask=0022,dmask=0022"));
293 assert_se(mount_option_mangle("rw,relatime,fmask=0022,dmask=0022,\"hogehoge", MS_RDONLY
, &f
, &opts
) < 0);
296 int main(int argc
, char *argv
[]) {
298 log_set_max_level(LOG_DEBUG
);
300 test_mount_propagation_flags("shared", 0, MS_SHARED
);
301 test_mount_propagation_flags("slave", 0, MS_SLAVE
);
302 test_mount_propagation_flags("private", 0, MS_PRIVATE
);
303 test_mount_propagation_flags(NULL
, 0, 0);
304 test_mount_propagation_flags("", 0, 0);
305 test_mount_propagation_flags("xxxx", -EINVAL
, 0);
306 test_mount_propagation_flags(" ", -EINVAL
, 0);
309 test_path_is_mount_point();
310 test_mount_option_mangle();