]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/test/test-path-util.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Zbigniew Jędrzejewski-Szmek
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
23 #include <sys/mount.h>
26 #include "alloc-util.h"
29 #include "mount-util.h"
30 #include "path-util.h"
32 #include "string-util.h"
36 #define test_path_compare(a, b, result) { \
37 assert_se(path_compare(a, b) == result); \
38 assert_se(path_compare(b, a) == -result); \
39 assert_se(path_equal(a, b) == !result); \
40 assert_se(path_equal(b, a) == !result); \
43 static void test_path(void) {
44 _cleanup_close_
int fd
= -1;
46 test_path_compare("/goo", "/goo", 0);
47 test_path_compare("/goo", "/goo", 0);
48 test_path_compare("//goo", "/goo", 0);
49 test_path_compare("//goo/////", "/goo", 0);
50 test_path_compare("goo/////", "goo", 0);
52 test_path_compare("/goo/boo", "/goo//boo", 0);
53 test_path_compare("//goo/boo", "/goo/boo//", 0);
55 test_path_compare("/", "///", 0);
57 test_path_compare("/x", "x/", 1);
58 test_path_compare("x/", "/", -1);
60 test_path_compare("/x/./y", "x/y", 1);
61 test_path_compare("x/.y", "x/y", -1);
63 test_path_compare("foo", "/foo", -1);
64 test_path_compare("/foo", "/foo/bar", -1);
65 test_path_compare("/foo/aaa", "/foo/b", -1);
66 test_path_compare("/foo/aaa", "/foo/b/a", -1);
67 test_path_compare("/foo/a", "/foo/aaa", -1);
68 test_path_compare("/foo/a/b", "/foo/aaa", -1);
70 assert_se(path_is_absolute("/"));
71 assert_se(!path_is_absolute("./"));
73 assert_se(is_path("/dir"));
74 assert_se(is_path("a/b"));
75 assert_se(!is_path("."));
77 assert_se(streq(basename("./aa/bb/../file.da."), "file.da."));
78 assert_se(streq(basename("/aa///.file"), ".file"));
79 assert_se(streq(basename("/aa///file..."), "file..."));
80 assert_se(streq(basename("file.../"), ""));
82 fd
= open("/", O_RDONLY
|O_CLOEXEC
|O_DIRECTORY
|O_NOCTTY
);
84 assert_se(fd_is_mount_point(fd
, "/", 0) > 0);
87 char p1
[] = "aaa/bbb////ccc";
88 char p2
[] = "//aaa/.////ccc";
91 assert_se(path_equal(path_kill_slashes(p1
), "aaa/bbb/ccc"));
92 assert_se(path_equal(path_kill_slashes(p2
), "/aaa/./ccc"));
93 assert_se(path_equal(path_kill_slashes(p3
), "/./"));
97 static void test_find_binary(const char *self
) {
100 assert_se(find_binary("/bin/sh", &p
) == 0);
102 assert_se(path_equal(p
, "/bin/sh"));
105 assert_se(find_binary(self
, &p
) == 0);
107 assert_se(endswith(p
, "/test-path-util"));
108 assert_se(path_is_absolute(p
));
111 assert_se(find_binary("sh", &p
) == 0);
113 assert_se(endswith(p
, "/sh"));
114 assert_se(path_is_absolute(p
));
117 assert_se(find_binary("xxxx-xxxx", &p
) == -ENOENT
);
118 assert_se(find_binary("/some/dir/xxxx-xxxx", &p
) == -ENOENT
);
121 static void test_prefixes(void) {
122 static const char* values
[] = { "/a/b/c/d", "/a/b/c", "/a/b", "/a", "", NULL
};
128 PATH_FOREACH_PREFIX_MORE(s
, "/a/b/c/d") {
129 log_error("---%s---", s
);
130 assert_se(streq(s
, values
[i
++]));
132 assert_se(values
[i
] == NULL
);
135 PATH_FOREACH_PREFIX(s
, "/a/b/c/d") {
136 log_error("---%s---", s
);
137 assert_se(streq(s
, values
[i
++]));
139 assert_se(values
[i
] == NULL
);
142 PATH_FOREACH_PREFIX_MORE(s
, "////a////b////c///d///////")
143 assert_se(streq(s
, values
[i
++]));
144 assert_se(values
[i
] == NULL
);
147 PATH_FOREACH_PREFIX(s
, "////a////b////c///d///////")
148 assert_se(streq(s
, values
[i
++]));
149 assert_se(values
[i
] == NULL
);
151 PATH_FOREACH_PREFIX(s
, "////")
152 assert_not_reached("Wut?");
155 PATH_FOREACH_PREFIX_MORE(s
, "////") {
157 assert_se(streq(s
, ""));
162 PATH_FOREACH_PREFIX(s
, "")
163 assert_not_reached("wut?");
166 PATH_FOREACH_PREFIX_MORE(s
, "") {
168 assert_se(streq(s
, ""));
173 static void test_path_join(void) {
175 #define test_join(root, path, rest, expected) { \
176 _cleanup_free_ char *z = NULL; \
177 z = path_join(root, path, rest); \
178 assert_se(streq(z, expected)); \
181 test_join("/root", "/a/b", "/c", "/root/a/b/c");
182 test_join("/root", "a/b", "c", "/root/a/b/c");
183 test_join("/root", "/a/b", "c", "/root/a/b/c");
184 test_join("/root", "/", "c", "/root/c");
185 test_join("/root", "/", NULL
, "/root/");
187 test_join(NULL
, "/a/b", "/c", "/a/b/c");
188 test_join(NULL
, "a/b", "c", "a/b/c");
189 test_join(NULL
, "/a/b", "c", "/a/b/c");
190 test_join(NULL
, "/", "c", "/c");
191 test_join(NULL
, "/", NULL
, "/");
194 static void test_fsck_exists(void) {
195 /* Ensure we use a sane default for PATH. */
198 /* fsck.minix is provided by util-linux and will probably exist. */
199 assert_se(fsck_exists("minix") == 1);
201 assert_se(fsck_exists("AbCdE") == 0);
202 assert_se(fsck_exists("/../bin/") == 0);
205 static void test_make_relative(void) {
208 assert_se(path_make_relative("some/relative/path", "/some/path", &result
) < 0);
209 assert_se(path_make_relative("/some/path", "some/relative/path", &result
) < 0);
211 #define test(from_dir, to_path, expected) { \
212 _cleanup_free_ char *z = NULL; \
213 path_make_relative(from_dir, to_path, &z); \
214 assert_se(streq(z, expected)); \
218 test("/", "/some/path", "some/path");
219 test("/some/path", "/some/path", ".");
220 test("/some/path", "/some/path/in/subdir", "in/subdir");
221 test("/some/path", "/", "../..");
222 test("/some/path", "/some/other/path", "../other/path");
223 test("//extra/////slashes///won't////fool///anybody//", "////extra///slashes////are/just///fine///", "../../../are/just/fine");
226 static void test_strv_resolve(void) {
227 char tmp_dir
[] = "/tmp/test-path-util-XXXXXX";
228 _cleanup_strv_free_
char **search_dirs
= NULL
;
229 _cleanup_strv_free_
char **absolute_dirs
= NULL
;
232 assert_se(mkdtemp(tmp_dir
) != NULL
);
234 search_dirs
= strv_new("/dir1", "/dir2", "/dir3", NULL
);
235 assert_se(search_dirs
);
236 STRV_FOREACH(d
, search_dirs
) {
237 char *p
= strappend(tmp_dir
, *d
);
239 assert_se(strv_push(&absolute_dirs
, p
) == 0);
242 assert_se(mkdir(absolute_dirs
[0], 0700) == 0);
243 assert_se(mkdir(absolute_dirs
[1], 0700) == 0);
244 assert_se(symlink("dir2", absolute_dirs
[2]) == 0);
246 path_strv_resolve(search_dirs
, tmp_dir
);
247 assert_se(streq(search_dirs
[0], "/dir1"));
248 assert_se(streq(search_dirs
[1], "/dir2"));
249 assert_se(streq(search_dirs
[2], "/dir2"));
251 assert_se(rm_rf(tmp_dir
, REMOVE_ROOT
|REMOVE_PHYSICAL
) == 0);
254 static void test_path_startswith(void) {
255 assert_se(path_startswith("/foo/bar/barfoo/", "/foo"));
256 assert_se(path_startswith("/foo/bar/barfoo/", "/foo/"));
257 assert_se(path_startswith("/foo/bar/barfoo/", "/"));
258 assert_se(path_startswith("/foo/bar/barfoo/", "////"));
259 assert_se(path_startswith("/foo/bar/barfoo/", "/foo//bar/////barfoo///"));
260 assert_se(path_startswith("/foo/bar/barfoo/", "/foo/bar/barfoo////"));
261 assert_se(path_startswith("/foo/bar/barfoo/", "/foo/bar///barfoo/"));
262 assert_se(path_startswith("/foo/bar/barfoo/", "/foo////bar/barfoo/"));
263 assert_se(path_startswith("/foo/bar/barfoo/", "////foo/bar/barfoo/"));
264 assert_se(path_startswith("/foo/bar/barfoo/", "/foo/bar/barfoo"));
266 assert_se(!path_startswith("/foo/bar/barfoo/", "/foo/bar/barfooa/"));
267 assert_se(!path_startswith("/foo/bar/barfoo/", "/foo/bar/barfooa"));
268 assert_se(!path_startswith("/foo/bar/barfoo/", ""));
269 assert_se(!path_startswith("/foo/bar/barfoo/", "/bar/foo"));
270 assert_se(!path_startswith("/foo/bar/barfoo/", "/f/b/b/"));
273 static void test_prefix_root_one(const char *r
, const char *p
, const char *expected
) {
274 _cleanup_free_
char *s
= NULL
;
277 assert_se(s
= prefix_root(r
, p
));
278 assert_se(streq_ptr(s
, expected
));
280 t
= prefix_roota(r
, p
);
282 assert_se(streq_ptr(t
, expected
));
285 static void test_prefix_root(void) {
286 test_prefix_root_one("/", "/foo", "/foo");
287 test_prefix_root_one(NULL
, "/foo", "/foo");
288 test_prefix_root_one("", "/foo", "/foo");
289 test_prefix_root_one("///", "/foo", "/foo");
290 test_prefix_root_one("/", "////foo", "/foo");
291 test_prefix_root_one(NULL
, "////foo", "/foo");
293 test_prefix_root_one("/foo", "/bar", "/foo/bar");
294 test_prefix_root_one("/foo", "bar", "/foo/bar");
295 test_prefix_root_one("foo", "bar", "foo/bar");
296 test_prefix_root_one("/foo/", "/bar", "/foo/bar");
297 test_prefix_root_one("/foo/", "//bar", "/foo/bar");
298 test_prefix_root_one("/foo///", "//bar", "/foo/bar");
301 static void test_path_is_mount_point(void) {
303 char tmp_dir
[] = "/tmp/test-path-is-mount-point-XXXXXX";
304 _cleanup_free_
char *file1
= NULL
, *file2
= NULL
, *link1
= NULL
, *link2
= NULL
;
305 _cleanup_free_
char *dir1
= NULL
, *dir1file
= NULL
, *dirlink1
= NULL
, *dirlink1file
= NULL
;
306 _cleanup_free_
char *dir2
= NULL
, *dir2file
= NULL
;
308 assert_se(path_is_mount_point("/", AT_SYMLINK_FOLLOW
) > 0);
309 assert_se(path_is_mount_point("/", 0) > 0);
311 assert_se(path_is_mount_point("/proc", AT_SYMLINK_FOLLOW
) > 0);
312 assert_se(path_is_mount_point("/proc", 0) > 0);
314 assert_se(path_is_mount_point("/proc/1", AT_SYMLINK_FOLLOW
) == 0);
315 assert_se(path_is_mount_point("/proc/1", 0) == 0);
317 assert_se(path_is_mount_point("/sys", AT_SYMLINK_FOLLOW
) > 0);
318 assert_se(path_is_mount_point("/sys", 0) > 0);
320 /* we'll create a hierarchy of different kinds of dir/file/link
323 * <tmp>/file1, <tmp>/file2
324 * <tmp>/link1 -> file1, <tmp>/link2 -> file2
327 * <tmp>/dirlink1 -> dir1
328 * <tmp>/dirlink1file -> dirlink1/file
333 /* file mountpoints */
334 assert_se(mkdtemp(tmp_dir
) != NULL
);
335 file1
= path_join(NULL
, tmp_dir
, "file1");
337 file2
= path_join(NULL
, tmp_dir
, "file2");
339 fd
= open(file1
, O_WRONLY
|O_CREAT
|O_EXCL
|O_CLOEXEC
, 0664);
342 fd
= open(file2
, O_WRONLY
|O_CREAT
|O_EXCL
|O_CLOEXEC
, 0664);
345 link1
= path_join(NULL
, tmp_dir
, "link1");
347 assert_se(symlink("file1", link1
) == 0);
348 link2
= path_join(NULL
, tmp_dir
, "link2");
350 assert_se(symlink("file2", link2
) == 0);
352 assert_se(path_is_mount_point(file1
, AT_SYMLINK_FOLLOW
) == 0);
353 assert_se(path_is_mount_point(file1
, 0) == 0);
354 assert_se(path_is_mount_point(link1
, AT_SYMLINK_FOLLOW
) == 0);
355 assert_se(path_is_mount_point(link1
, 0) == 0);
357 /* directory mountpoints */
358 dir1
= path_join(NULL
, tmp_dir
, "dir1");
360 assert_se(mkdir(dir1
, 0755) == 0);
361 dirlink1
= path_join(NULL
, tmp_dir
, "dirlink1");
363 assert_se(symlink("dir1", dirlink1
) == 0);
364 dirlink1file
= path_join(NULL
, tmp_dir
, "dirlink1file");
365 assert_se(dirlink1file
);
366 assert_se(symlink("dirlink1/file", dirlink1file
) == 0);
367 dir2
= path_join(NULL
, tmp_dir
, "dir2");
369 assert_se(mkdir(dir2
, 0755) == 0);
371 assert_se(path_is_mount_point(dir1
, AT_SYMLINK_FOLLOW
) == 0);
372 assert_se(path_is_mount_point(dir1
, 0) == 0);
373 assert_se(path_is_mount_point(dirlink1
, AT_SYMLINK_FOLLOW
) == 0);
374 assert_se(path_is_mount_point(dirlink1
, 0) == 0);
376 /* file in subdirectory mountpoints */
377 dir1file
= path_join(NULL
, dir1
, "file");
379 fd
= open(dir1file
, O_WRONLY
|O_CREAT
|O_EXCL
|O_CLOEXEC
, 0664);
383 assert_se(path_is_mount_point(dir1file
, AT_SYMLINK_FOLLOW
) == 0);
384 assert_se(path_is_mount_point(dir1file
, 0) == 0);
385 assert_se(path_is_mount_point(dirlink1file
, AT_SYMLINK_FOLLOW
) == 0);
386 assert_se(path_is_mount_point(dirlink1file
, 0) == 0);
388 /* these tests will only work as root */
389 if (mount(file1
, file2
, NULL
, MS_BIND
, NULL
) >= 0) {
390 int rt
, rf
, rlt
, rlf
, rl1t
, rl1f
;
393 /* capture results in vars, to avoid dangling mounts on failure */
394 rf
= path_is_mount_point(file2
, 0);
395 rt
= path_is_mount_point(file2
, AT_SYMLINK_FOLLOW
);
396 rlf
= path_is_mount_point(link2
, 0);
397 rlt
= path_is_mount_point(link2
, AT_SYMLINK_FOLLOW
);
399 assert_se(umount(file2
) == 0);
407 dir2file
= path_join(NULL
, dir2
, "file");
409 fd
= open(dir2file
, O_WRONLY
|O_CREAT
|O_EXCL
|O_CLOEXEC
, 0664);
413 assert_se(mount(dir2
, dir1
, NULL
, MS_BIND
, NULL
) >= 0);
415 rf
= path_is_mount_point(dir1
, 0);
416 rt
= path_is_mount_point(dir1
, AT_SYMLINK_FOLLOW
);
417 rlf
= path_is_mount_point(dirlink1
, 0);
418 rlt
= path_is_mount_point(dirlink1
, AT_SYMLINK_FOLLOW
);
419 /* its parent is a mount point, but not /file itself */
420 rl1f
= path_is_mount_point(dirlink1file
, 0);
421 rl1t
= path_is_mount_point(dirlink1file
, AT_SYMLINK_FOLLOW
);
423 assert_se(umount(dir1
) == 0);
429 assert_se(rl1f
== 0);
430 assert_se(rl1t
== 0);
433 printf("Skipping bind mount file test: %m\n");
435 assert_se(rm_rf(tmp_dir
, REMOVE_ROOT
|REMOVE_PHYSICAL
) == 0);
438 int main(int argc
, char **argv
) {
440 test_find_binary(argv
[0]);
444 test_make_relative();
446 test_path_startswith();
448 test_path_is_mount_point();