]>
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>
27 #include "path-util.h"
29 #include "string-util.h"
33 #define test_path_compare(a, b, result) { \
34 assert_se(path_compare(a, b) == result); \
35 assert_se(path_compare(b, a) == -result); \
36 assert_se(path_equal(a, b) == !result); \
37 assert_se(path_equal(b, a) == !result); \
40 static void test_path(void) {
41 _cleanup_close_
int fd
= -1;
43 test_path_compare("/goo", "/goo", 0);
44 test_path_compare("/goo", "/goo", 0);
45 test_path_compare("//goo", "/goo", 0);
46 test_path_compare("//goo/////", "/goo", 0);
47 test_path_compare("goo/////", "goo", 0);
49 test_path_compare("/goo/boo", "/goo//boo", 0);
50 test_path_compare("//goo/boo", "/goo/boo//", 0);
52 test_path_compare("/", "///", 0);
54 test_path_compare("/x", "x/", 1);
55 test_path_compare("x/", "/", -1);
57 test_path_compare("/x/./y", "x/y", 1);
58 test_path_compare("x/.y", "x/y", -1);
60 test_path_compare("foo", "/foo", -1);
61 test_path_compare("/foo", "/foo/bar", -1);
62 test_path_compare("/foo/aaa", "/foo/b", -1);
63 test_path_compare("/foo/aaa", "/foo/b/a", -1);
64 test_path_compare("/foo/a", "/foo/aaa", -1);
65 test_path_compare("/foo/a/b", "/foo/aaa", -1);
67 assert_se(path_is_absolute("/"));
68 assert_se(!path_is_absolute("./"));
70 assert_se(is_path("/dir"));
71 assert_se(is_path("a/b"));
72 assert_se(!is_path("."));
74 assert_se(streq(basename("./aa/bb/../file.da."), "file.da."));
75 assert_se(streq(basename("/aa///.file"), ".file"));
76 assert_se(streq(basename("/aa///file..."), "file..."));
77 assert_se(streq(basename("file.../"), ""));
79 #define test_parent(x, y) { \
80 _cleanup_free_ char *z = NULL; \
81 int r = path_get_parent(x, &z); \
82 printf("expected: %s\n", y ? y : "error"); \
83 printf("actual: %s\n", r<0 ? "error" : z); \
84 assert_se((y==NULL) ^ (r==0)); \
85 assert_se(y==NULL || path_equal(z, y)); \
88 test_parent("./aa/bb/../file.da.", "./aa/bb/..");
89 test_parent("/aa///.file", "/aa///");
90 test_parent("/aa///file...", "/aa///");
91 test_parent("file.../", NULL
);
93 fd
= open("/", O_RDONLY
|O_CLOEXEC
|O_DIRECTORY
|O_NOCTTY
);
95 assert_se(fd_is_mount_point(fd
, "/", 0) > 0);
98 char p1
[] = "aaa/bbb////ccc";
99 char p2
[] = "//aaa/.////ccc";
102 assert_se(path_equal(path_kill_slashes(p1
), "aaa/bbb/ccc"));
103 assert_se(path_equal(path_kill_slashes(p2
), "/aaa/./ccc"));
104 assert_se(path_equal(path_kill_slashes(p3
), "/./"));
108 static void test_find_binary(const char *self
) {
111 assert_se(find_binary("/bin/sh", &p
) == 0);
113 assert_se(path_equal(p
, "/bin/sh"));
116 assert_se(find_binary(self
, &p
) == 0);
118 assert_se(endswith(p
, "/test-path-util"));
119 assert_se(path_is_absolute(p
));
122 assert_se(find_binary("sh", &p
) == 0);
124 assert_se(endswith(p
, "/sh"));
125 assert_se(path_is_absolute(p
));
128 assert_se(find_binary("xxxx-xxxx", &p
) == -ENOENT
);
129 assert_se(find_binary("/some/dir/xxxx-xxxx", &p
) == -ENOENT
);
132 static void test_prefixes(void) {
133 static const char* values
[] = { "/a/b/c/d", "/a/b/c", "/a/b", "/a", "", NULL
};
139 PATH_FOREACH_PREFIX_MORE(s
, "/a/b/c/d") {
140 log_error("---%s---", s
);
141 assert_se(streq(s
, values
[i
++]));
143 assert_se(values
[i
] == NULL
);
146 PATH_FOREACH_PREFIX(s
, "/a/b/c/d") {
147 log_error("---%s---", s
);
148 assert_se(streq(s
, values
[i
++]));
150 assert_se(values
[i
] == NULL
);
153 PATH_FOREACH_PREFIX_MORE(s
, "////a////b////c///d///////")
154 assert_se(streq(s
, values
[i
++]));
155 assert_se(values
[i
] == NULL
);
158 PATH_FOREACH_PREFIX(s
, "////a////b////c///d///////")
159 assert_se(streq(s
, values
[i
++]));
160 assert_se(values
[i
] == NULL
);
162 PATH_FOREACH_PREFIX(s
, "////")
163 assert_not_reached("Wut?");
166 PATH_FOREACH_PREFIX_MORE(s
, "////") {
168 assert_se(streq(s
, ""));
173 PATH_FOREACH_PREFIX(s
, "")
174 assert_not_reached("wut?");
177 PATH_FOREACH_PREFIX_MORE(s
, "") {
179 assert_se(streq(s
, ""));
184 static void test_path_join(void) {
186 #define test_join(root, path, rest, expected) { \
187 _cleanup_free_ char *z = NULL; \
188 z = path_join(root, path, rest); \
189 assert_se(streq(z, expected)); \
192 test_join("/root", "/a/b", "/c", "/root/a/b/c");
193 test_join("/root", "a/b", "c", "/root/a/b/c");
194 test_join("/root", "/a/b", "c", "/root/a/b/c");
195 test_join("/root", "/", "c", "/root/c");
196 test_join("/root", "/", NULL
, "/root/");
198 test_join(NULL
, "/a/b", "/c", "/a/b/c");
199 test_join(NULL
, "a/b", "c", "a/b/c");
200 test_join(NULL
, "/a/b", "c", "/a/b/c");
201 test_join(NULL
, "/", "c", "/c");
202 test_join(NULL
, "/", NULL
, "/");
205 static void test_fsck_exists(void) {
206 /* Ensure we use a sane default for PATH. */
209 /* fsck.minix is provided by util-linux and will probably exist. */
210 assert_se(fsck_exists("minix") == 1);
212 assert_se(fsck_exists("AbCdE") == 0);
213 assert_se(fsck_exists("/../bin/") == 0);
216 static void test_make_relative(void) {
219 assert_se(path_make_relative("some/relative/path", "/some/path", &result
) < 0);
220 assert_se(path_make_relative("/some/path", "some/relative/path", &result
) < 0);
222 #define test(from_dir, to_path, expected) { \
223 _cleanup_free_ char *z = NULL; \
224 path_make_relative(from_dir, to_path, &z); \
225 assert_se(streq(z, expected)); \
229 test("/", "/some/path", "some/path");
230 test("/some/path", "/some/path", ".");
231 test("/some/path", "/some/path/in/subdir", "in/subdir");
232 test("/some/path", "/", "../..");
233 test("/some/path", "/some/other/path", "../other/path");
234 test("//extra/////slashes///won't////fool///anybody//", "////extra///slashes////are/just///fine///", "../../../are/just/fine");
237 static void test_strv_resolve(void) {
238 char tmp_dir
[] = "/tmp/test-path-util-XXXXXX";
239 _cleanup_strv_free_
char **search_dirs
= NULL
;
240 _cleanup_strv_free_
char **absolute_dirs
= NULL
;
243 assert_se(mkdtemp(tmp_dir
) != NULL
);
245 search_dirs
= strv_new("/dir1", "/dir2", "/dir3", NULL
);
246 assert_se(search_dirs
);
247 STRV_FOREACH(d
, search_dirs
) {
248 char *p
= strappend(tmp_dir
, *d
);
250 assert_se(strv_push(&absolute_dirs
, p
) == 0);
253 assert_se(mkdir(absolute_dirs
[0], 0700) == 0);
254 assert_se(mkdir(absolute_dirs
[1], 0700) == 0);
255 assert_se(symlink("dir2", absolute_dirs
[2]) == 0);
257 path_strv_resolve(search_dirs
, tmp_dir
);
258 assert_se(streq(search_dirs
[0], "/dir1"));
259 assert_se(streq(search_dirs
[1], "/dir2"));
260 assert_se(streq(search_dirs
[2], "/dir2"));
262 assert_se(rm_rf(tmp_dir
, REMOVE_ROOT
|REMOVE_PHYSICAL
) == 0);
265 static void test_path_startswith(void) {
266 assert_se(path_startswith("/foo/bar/barfoo/", "/foo"));
267 assert_se(path_startswith("/foo/bar/barfoo/", "/foo/"));
268 assert_se(path_startswith("/foo/bar/barfoo/", "/"));
269 assert_se(path_startswith("/foo/bar/barfoo/", "////"));
270 assert_se(path_startswith("/foo/bar/barfoo/", "/foo//bar/////barfoo///"));
271 assert_se(path_startswith("/foo/bar/barfoo/", "/foo/bar/barfoo////"));
272 assert_se(path_startswith("/foo/bar/barfoo/", "/foo/bar///barfoo/"));
273 assert_se(path_startswith("/foo/bar/barfoo/", "/foo////bar/barfoo/"));
274 assert_se(path_startswith("/foo/bar/barfoo/", "////foo/bar/barfoo/"));
275 assert_se(path_startswith("/foo/bar/barfoo/", "/foo/bar/barfoo"));
277 assert_se(!path_startswith("/foo/bar/barfoo/", "/foo/bar/barfooa/"));
278 assert_se(!path_startswith("/foo/bar/barfoo/", "/foo/bar/barfooa"));
279 assert_se(!path_startswith("/foo/bar/barfoo/", ""));
280 assert_se(!path_startswith("/foo/bar/barfoo/", "/bar/foo"));
281 assert_se(!path_startswith("/foo/bar/barfoo/", "/f/b/b/"));
284 static void test_prefix_root_one(const char *r
, const char *p
, const char *expected
) {
285 _cleanup_free_
char *s
= NULL
;
288 assert_se(s
= prefix_root(r
, p
));
289 assert_se(streq_ptr(s
, expected
));
291 t
= prefix_roota(r
, p
);
293 assert_se(streq_ptr(t
, expected
));
296 static void test_prefix_root(void) {
297 test_prefix_root_one("/", "/foo", "/foo");
298 test_prefix_root_one(NULL
, "/foo", "/foo");
299 test_prefix_root_one("", "/foo", "/foo");
300 test_prefix_root_one("///", "/foo", "/foo");
301 test_prefix_root_one("/", "////foo", "/foo");
302 test_prefix_root_one(NULL
, "////foo", "/foo");
304 test_prefix_root_one("/foo", "/bar", "/foo/bar");
305 test_prefix_root_one("/foo", "bar", "/foo/bar");
306 test_prefix_root_one("foo", "bar", "foo/bar");
307 test_prefix_root_one("/foo/", "/bar", "/foo/bar");
308 test_prefix_root_one("/foo/", "//bar", "/foo/bar");
309 test_prefix_root_one("/foo///", "//bar", "/foo/bar");
312 static void test_path_is_mount_point(void) {
314 char tmp_dir
[] = "/tmp/test-path-is-mount-point-XXXXXX";
315 _cleanup_free_
char *file1
= NULL
, *file2
= NULL
, *link1
= NULL
, *link2
= NULL
;
316 _cleanup_free_
char *dir1
= NULL
, *dir1file
= NULL
, *dirlink1
= NULL
, *dirlink1file
= NULL
;
317 _cleanup_free_
char *dir2
= NULL
, *dir2file
= NULL
;
319 assert_se(path_is_mount_point("/", AT_SYMLINK_FOLLOW
) > 0);
320 assert_se(path_is_mount_point("/", 0) > 0);
322 assert_se(path_is_mount_point("/proc", AT_SYMLINK_FOLLOW
) > 0);
323 assert_se(path_is_mount_point("/proc", 0) > 0);
325 assert_se(path_is_mount_point("/proc/1", AT_SYMLINK_FOLLOW
) == 0);
326 assert_se(path_is_mount_point("/proc/1", 0) == 0);
328 assert_se(path_is_mount_point("/sys", AT_SYMLINK_FOLLOW
) > 0);
329 assert_se(path_is_mount_point("/sys", 0) > 0);
331 /* we'll create a hierarchy of different kinds of dir/file/link
334 * <tmp>/file1, <tmp>/file2
335 * <tmp>/link1 -> file1, <tmp>/link2 -> file2
338 * <tmp>/dirlink1 -> dir1
339 * <tmp>/dirlink1file -> dirlink1/file
344 /* file mountpoints */
345 assert_se(mkdtemp(tmp_dir
) != NULL
);
346 file1
= path_join(NULL
, tmp_dir
, "file1");
348 file2
= path_join(NULL
, tmp_dir
, "file2");
350 fd
= open(file1
, O_WRONLY
|O_CREAT
|O_EXCL
|O_CLOEXEC
, 0664);
353 fd
= open(file2
, O_WRONLY
|O_CREAT
|O_EXCL
|O_CLOEXEC
, 0664);
356 link1
= path_join(NULL
, tmp_dir
, "link1");
358 assert_se(symlink("file1", link1
) == 0);
359 link2
= path_join(NULL
, tmp_dir
, "link2");
361 assert_se(symlink("file2", link2
) == 0);
363 assert_se(path_is_mount_point(file1
, AT_SYMLINK_FOLLOW
) == 0);
364 assert_se(path_is_mount_point(file1
, 0) == 0);
365 assert_se(path_is_mount_point(link1
, AT_SYMLINK_FOLLOW
) == 0);
366 assert_se(path_is_mount_point(link1
, 0) == 0);
368 /* directory mountpoints */
369 dir1
= path_join(NULL
, tmp_dir
, "dir1");
371 assert_se(mkdir(dir1
, 0755) == 0);
372 dirlink1
= path_join(NULL
, tmp_dir
, "dirlink1");
374 assert_se(symlink("dir1", dirlink1
) == 0);
375 dirlink1file
= path_join(NULL
, tmp_dir
, "dirlink1file");
376 assert_se(dirlink1file
);
377 assert_se(symlink("dirlink1/file", dirlink1file
) == 0);
378 dir2
= path_join(NULL
, tmp_dir
, "dir2");
380 assert_se(mkdir(dir2
, 0755) == 0);
382 assert_se(path_is_mount_point(dir1
, AT_SYMLINK_FOLLOW
) == 0);
383 assert_se(path_is_mount_point(dir1
, 0) == 0);
384 assert_se(path_is_mount_point(dirlink1
, AT_SYMLINK_FOLLOW
) == 0);
385 assert_se(path_is_mount_point(dirlink1
, 0) == 0);
387 /* file in subdirectory mountpoints */
388 dir1file
= path_join(NULL
, dir1
, "file");
390 fd
= open(dir1file
, O_WRONLY
|O_CREAT
|O_EXCL
|O_CLOEXEC
, 0664);
394 assert_se(path_is_mount_point(dir1file
, AT_SYMLINK_FOLLOW
) == 0);
395 assert_se(path_is_mount_point(dir1file
, 0) == 0);
396 assert_se(path_is_mount_point(dirlink1file
, AT_SYMLINK_FOLLOW
) == 0);
397 assert_se(path_is_mount_point(dirlink1file
, 0) == 0);
399 /* these tests will only work as root */
400 if (mount(file1
, file2
, NULL
, MS_BIND
, NULL
) >= 0) {
401 int rt
, rf
, rlt
, rlf
, rl1t
, rl1f
;
404 /* capture results in vars, to avoid dangling mounts on failure */
405 rf
= path_is_mount_point(file2
, 0);
406 rt
= path_is_mount_point(file2
, AT_SYMLINK_FOLLOW
);
407 rlf
= path_is_mount_point(link2
, 0);
408 rlt
= path_is_mount_point(link2
, AT_SYMLINK_FOLLOW
);
410 assert_se(umount(file2
) == 0);
418 dir2file
= path_join(NULL
, dir2
, "file");
420 fd
= open(dir2file
, O_WRONLY
|O_CREAT
|O_EXCL
|O_CLOEXEC
, 0664);
424 assert_se(mount(dir2
, dir1
, NULL
, MS_BIND
, NULL
) >= 0);
426 rf
= path_is_mount_point(dir1
, 0);
427 rt
= path_is_mount_point(dir1
, AT_SYMLINK_FOLLOW
);
428 rlf
= path_is_mount_point(dirlink1
, 0);
429 rlt
= path_is_mount_point(dirlink1
, AT_SYMLINK_FOLLOW
);
430 /* its parent is a mount point, but not /file itself */
431 rl1f
= path_is_mount_point(dirlink1file
, 0);
432 rl1t
= path_is_mount_point(dirlink1file
, AT_SYMLINK_FOLLOW
);
434 assert_se(umount(dir1
) == 0);
440 assert_se(rl1f
== 0);
441 assert_se(rl1t
== 0);
444 printf("Skipping bind mount file test: %m\n");
446 assert_se(rm_rf(tmp_dir
, REMOVE_ROOT
|REMOVE_PHYSICAL
) == 0);
449 int main(int argc
, char **argv
) {
451 test_find_binary(argv
[0]);
455 test_make_relative();
457 test_path_startswith();
459 test_path_is_mount_point();