]>
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"
18 static void test_mount_propagation_flags(const char *name
, int ret
, unsigned long expected
) {
21 assert_se(mount_propagation_flags_from_string(name
, &flags
) == ret
);
26 assert_se(flags
== expected
);
28 c
= mount_propagation_flags_to_string(flags
);
30 assert_se(isempty(c
));
32 assert_se(streq(c
, name
));
36 static void test_mnt_id(void) {
37 _cleanup_fclose_
FILE *f
= NULL
;
44 assert_se(f
= fopen("/proc/self/mountinfo", "re"));
45 assert_se(h
= hashmap_new(&trivial_hash_ops
));
48 _cleanup_free_
char *line
= NULL
, *path
= NULL
;
51 r
= read_line(f
, LONG_LINE_MAX
, &line
);
56 assert_se(sscanf(line
, "%i %*s %*s %*s %ms", &mnt_id
, &path
) == 2);
58 assert_se(hashmap_put(h
, INT_TO_PTR(mnt_id
), path
) >= 0);
62 HASHMAP_FOREACH_KEY(p
, k
, h
, i
) {
63 int mnt_id
= PTR_TO_INT(k
), mnt_id2
;
65 r
= path_get_mnt_id(p
, &mnt_id2
);
67 log_debug_errno(r
, "Failed to get the mnt id of %s: %m\n", p
);
71 log_debug("mnt id of %s is %i\n", p
, mnt_id2
);
73 if (mnt_id
== mnt_id2
)
76 /* The ids don't match? If so, then there are two mounts on the same path, let's check if that's really
78 assert_se(path_equal_ptr(hashmap_get(h
, INT_TO_PTR(mnt_id2
)), p
));
84 static void test_path_is_mount_point(void) {
86 char tmp_dir
[] = "/tmp/test-path-is-mount-point-XXXXXX";
87 _cleanup_free_
char *file1
= NULL
, *file2
= NULL
, *link1
= NULL
, *link2
= NULL
;
88 _cleanup_free_
char *dir1
= NULL
, *dir1file
= NULL
, *dirlink1
= NULL
, *dirlink1file
= NULL
;
89 _cleanup_free_
char *dir2
= NULL
, *dir2file
= NULL
;
91 assert_se(path_is_mount_point("/", NULL
, AT_SYMLINK_FOLLOW
) > 0);
92 assert_se(path_is_mount_point("/", NULL
, 0) > 0);
93 assert_se(path_is_mount_point("//", NULL
, AT_SYMLINK_FOLLOW
) > 0);
94 assert_se(path_is_mount_point("//", NULL
, 0) > 0);
96 assert_se(path_is_mount_point("/proc", NULL
, AT_SYMLINK_FOLLOW
) > 0);
97 assert_se(path_is_mount_point("/proc", 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);
101 assert_se(path_is_mount_point("/proc/1", NULL
, AT_SYMLINK_FOLLOW
) == 0);
102 assert_se(path_is_mount_point("/proc/1", 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);
106 assert_se(path_is_mount_point("/sys", NULL
, AT_SYMLINK_FOLLOW
) > 0);
107 assert_se(path_is_mount_point("/sys", 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);
111 /* we'll create a hierarchy of different kinds of dir/file/link
114 * <tmp>/file1, <tmp>/file2
115 * <tmp>/link1 -> file1, <tmp>/link2 -> file2
118 * <tmp>/dirlink1 -> dir1
119 * <tmp>/dirlink1file -> dirlink1/file
124 /* file mountpoints */
125 assert_se(mkdtemp(tmp_dir
) != NULL
);
126 file1
= path_join(NULL
, tmp_dir
, "file1");
128 file2
= path_join(NULL
, tmp_dir
, "file2");
130 fd
= open(file1
, O_WRONLY
|O_CREAT
|O_EXCL
|O_CLOEXEC
, 0664);
133 fd
= open(file2
, O_WRONLY
|O_CREAT
|O_EXCL
|O_CLOEXEC
, 0664);
136 link1
= path_join(NULL
, tmp_dir
, "link1");
138 assert_se(symlink("file1", link1
) == 0);
139 link2
= path_join(NULL
, tmp_dir
, "link2");
141 assert_se(symlink("file2", link2
) == 0);
143 assert_se(path_is_mount_point(file1
, NULL
, AT_SYMLINK_FOLLOW
) == 0);
144 assert_se(path_is_mount_point(file1
, NULL
, 0) == 0);
145 assert_se(path_is_mount_point(link1
, NULL
, AT_SYMLINK_FOLLOW
) == 0);
146 assert_se(path_is_mount_point(link1
, NULL
, 0) == 0);
148 /* directory mountpoints */
149 dir1
= path_join(NULL
, tmp_dir
, "dir1");
151 assert_se(mkdir(dir1
, 0755) == 0);
152 dirlink1
= path_join(NULL
, tmp_dir
, "dirlink1");
154 assert_se(symlink("dir1", dirlink1
) == 0);
155 dirlink1file
= path_join(NULL
, tmp_dir
, "dirlink1file");
156 assert_se(dirlink1file
);
157 assert_se(symlink("dirlink1/file", dirlink1file
) == 0);
158 dir2
= path_join(NULL
, tmp_dir
, "dir2");
160 assert_se(mkdir(dir2
, 0755) == 0);
162 assert_se(path_is_mount_point(dir1
, NULL
, AT_SYMLINK_FOLLOW
) == 0);
163 assert_se(path_is_mount_point(dir1
, NULL
, 0) == 0);
164 assert_se(path_is_mount_point(dirlink1
, NULL
, AT_SYMLINK_FOLLOW
) == 0);
165 assert_se(path_is_mount_point(dirlink1
, NULL
, 0) == 0);
167 /* file in subdirectory mountpoints */
168 dir1file
= path_join(NULL
, dir1
, "file");
170 fd
= open(dir1file
, O_WRONLY
|O_CREAT
|O_EXCL
|O_CLOEXEC
, 0664);
174 assert_se(path_is_mount_point(dir1file
, NULL
, AT_SYMLINK_FOLLOW
) == 0);
175 assert_se(path_is_mount_point(dir1file
, NULL
, 0) == 0);
176 assert_se(path_is_mount_point(dirlink1file
, NULL
, AT_SYMLINK_FOLLOW
) == 0);
177 assert_se(path_is_mount_point(dirlink1file
, NULL
, 0) == 0);
179 /* these tests will only work as root */
180 if (mount(file1
, file2
, NULL
, MS_BIND
, NULL
) >= 0) {
181 int rf
, rt
, rdf
, rdt
, rlf
, rlt
, rl1f
, rl1t
;
185 /* capture results in vars, to avoid dangling mounts on failure */
186 log_info("%s: %s", __func__
, file2
);
187 rf
= path_is_mount_point(file2
, NULL
, 0);
188 rt
= path_is_mount_point(file2
, NULL
, AT_SYMLINK_FOLLOW
);
190 file2d
= strjoina(file2
, "/");
191 log_info("%s: %s", __func__
, file2d
);
192 rdf
= path_is_mount_point(file2d
, NULL
, 0);
193 rdt
= path_is_mount_point(file2d
, NULL
, AT_SYMLINK_FOLLOW
);
195 log_info("%s: %s", __func__
, link2
);
196 rlf
= path_is_mount_point(link2
, NULL
, 0);
197 rlt
= path_is_mount_point(link2
, NULL
, AT_SYMLINK_FOLLOW
);
199 assert_se(umount(file2
) == 0);
203 assert_se(rdf
== -ENOTDIR
);
204 assert_se(rdt
== -ENOTDIR
);
209 dir2file
= path_join(NULL
, dir2
, "file");
211 fd
= open(dir2file
, O_WRONLY
|O_CREAT
|O_EXCL
|O_CLOEXEC
, 0664);
215 assert_se(mount(dir2
, dir1
, NULL
, MS_BIND
, NULL
) >= 0);
217 log_info("%s: %s", __func__
, dir1
);
218 rf
= path_is_mount_point(dir1
, NULL
, 0);
219 rt
= path_is_mount_point(dir1
, NULL
, AT_SYMLINK_FOLLOW
);
220 log_info("%s: %s", __func__
, dirlink1
);
221 rlf
= path_is_mount_point(dirlink1
, NULL
, 0);
222 rlt
= path_is_mount_point(dirlink1
, NULL
, AT_SYMLINK_FOLLOW
);
223 log_info("%s: %s", __func__
, dirlink1file
);
224 /* its parent is a mount point, but not /file itself */
225 rl1f
= path_is_mount_point(dirlink1file
, NULL
, 0);
226 rl1t
= path_is_mount_point(dirlink1file
, NULL
, AT_SYMLINK_FOLLOW
);
228 assert_se(umount(dir1
) == 0);
234 assert_se(rl1f
== 0);
235 assert_se(rl1t
== 0);
238 printf("Skipping bind mount file test: %m\n");
240 assert_se(rm_rf(tmp_dir
, REMOVE_ROOT
|REMOVE_PHYSICAL
) == 0);
243 static void test_mount_option_mangle(void) {
247 assert_se(mount_option_mangle(NULL
, MS_RDONLY
|MS_NOSUID
, &f
, &opts
) == 0);
248 assert_se(f
== (MS_RDONLY
|MS_NOSUID
));
249 assert_se(opts
== NULL
);
251 assert_se(mount_option_mangle("", MS_RDONLY
|MS_NOSUID
, &f
, &opts
) == 0);
252 assert_se(f
== (MS_RDONLY
|MS_NOSUID
));
253 assert_se(opts
== NULL
);
255 assert_se(mount_option_mangle("ro,nosuid,nodev,noexec", 0, &f
, &opts
) == 0);
256 assert_se(f
== (MS_RDONLY
|MS_NOSUID
|MS_NODEV
|MS_NOEXEC
));
257 assert_se(opts
== NULL
);
259 assert_se(mount_option_mangle("ro,nosuid,nodev,noexec,mode=755", 0, &f
, &opts
) == 0);
260 assert_se(f
== (MS_RDONLY
|MS_NOSUID
|MS_NODEV
|MS_NOEXEC
));
261 assert_se(streq(opts
, "mode=755"));
264 assert_se(mount_option_mangle("rw,nosuid,foo,hogehoge,nodev,mode=755", 0, &f
, &opts
) == 0);
265 assert_se(f
== (MS_NOSUID
|MS_NODEV
));
266 assert_se(streq(opts
, "foo,hogehoge,mode=755"));
269 assert_se(mount_option_mangle("rw,nosuid,nodev,noexec,relatime,net_cls,net_prio", MS_RDONLY
, &f
, &opts
) == 0);
270 assert_se(f
== (MS_NOSUID
|MS_NODEV
|MS_NOEXEC
|MS_RELATIME
));
271 assert_se(streq(opts
, "net_cls,net_prio"));
274 assert_se(mount_option_mangle("rw,nosuid,nodev,relatime,size=1630748k,mode=700,uid=1000,gid=1000", MS_RDONLY
, &f
, &opts
) == 0);
275 assert_se(f
== (MS_NOSUID
|MS_NODEV
|MS_RELATIME
));
276 assert_se(streq(opts
, "size=1630748k,mode=700,uid=1000,gid=1000"));
279 assert_se(mount_option_mangle("size=1630748k,rw,gid=1000,,,nodev,relatime,,mode=700,nosuid,uid=1000", MS_RDONLY
, &f
, &opts
) == 0);
280 assert_se(f
== (MS_NOSUID
|MS_NODEV
|MS_RELATIME
));
281 assert_se(streq(opts
, "size=1630748k,gid=1000,mode=700,uid=1000"));
284 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);
285 assert_se(f
== (MS_NOSUID
|MS_NODEV
));
286 assert_se(streq(opts
, "size=8143984k,nr_inodes=2035996,mode=755"));
289 assert_se(mount_option_mangle("rw,relatime,fmask=0022,,,dmask=0022", MS_RDONLY
, &f
, &opts
) == 0);
290 assert_se(f
== MS_RELATIME
);
291 assert_se(streq(opts
, "fmask=0022,dmask=0022"));
294 assert_se(mount_option_mangle("rw,relatime,fmask=0022,dmask=0022,\"hogehoge", MS_RDONLY
, &f
, &opts
) < 0);
297 int main(int argc
, char *argv
[]) {
299 test_setup_logging(LOG_DEBUG
);
301 test_mount_propagation_flags("shared", 0, MS_SHARED
);
302 test_mount_propagation_flags("slave", 0, MS_SLAVE
);
303 test_mount_propagation_flags("private", 0, MS_PRIVATE
);
304 test_mount_propagation_flags(NULL
, 0, 0);
305 test_mount_propagation_flags("", 0, 0);
306 test_mount_propagation_flags("xxxx", -EINVAL
, 0);
307 test_mount_propagation_flags(" ", -EINVAL
, 0);
310 test_path_is_mount_point();
311 test_mount_option_mangle();