]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/test/test-path-util.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2013 Zbigniew Jędrzejewski-Szmek
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
24 #include "alloc-util.h"
27 #include "mount-util.h"
28 #include "path-util.h"
30 #include "stat-util.h"
31 #include "string-util.h"
35 #define test_path_compare(a, b, result) { \
36 assert_se(path_compare(a, b) == result); \
37 assert_se(path_compare(b, a) == -result); \
38 assert_se(path_equal(a, b) == !result); \
39 assert_se(path_equal(b, a) == !result); \
42 static void test_path(void) {
43 _cleanup_close_
int fd
= -1;
45 test_path_compare("/goo", "/goo", 0);
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);
51 test_path_compare("/goo/boo", "/goo//boo", 0);
52 test_path_compare("//goo/boo", "/goo/boo//", 0);
54 test_path_compare("/", "///", 0);
56 test_path_compare("/x", "x/", 1);
57 test_path_compare("x/", "/", -1);
59 test_path_compare("/x/./y", "x/y", 1);
60 test_path_compare("x/.y", "x/y", -1);
62 test_path_compare("foo", "/foo", -1);
63 test_path_compare("/foo", "/foo/bar", -1);
64 test_path_compare("/foo/aaa", "/foo/b", -1);
65 test_path_compare("/foo/aaa", "/foo/b/a", -1);
66 test_path_compare("/foo/a", "/foo/aaa", -1);
67 test_path_compare("/foo/a/b", "/foo/aaa", -1);
69 assert_se(path_is_absolute("/"));
70 assert_se(!path_is_absolute("./"));
72 assert_se(is_path("/dir"));
73 assert_se(is_path("a/b"));
74 assert_se(!is_path("."));
76 assert_se(streq(basename("./aa/bb/../file.da."), "file.da."));
77 assert_se(streq(basename("/aa///.file"), ".file"));
78 assert_se(streq(basename("/aa///file..."), "file..."));
79 assert_se(streq(basename("file.../"), ""));
81 fd
= open("/", O_RDONLY
|O_CLOEXEC
|O_DIRECTORY
|O_NOCTTY
);
83 assert_se(fd_is_mount_point(fd
, "/", 0) > 0);
86 char p1
[] = "aaa/bbb////ccc";
87 char p2
[] = "//aaa/.////ccc";
90 assert_se(path_equal(path_kill_slashes(p1
), "aaa/bbb/ccc"));
91 assert_se(path_equal(path_kill_slashes(p2
), "/aaa/./ccc"));
92 assert_se(path_equal(path_kill_slashes(p3
), "/./"));
95 assert_se(PATH_IN_SET("/bin", "/", "/bin", "/foo"));
96 assert_se(PATH_IN_SET("/bin", "/bin"));
97 assert_se(PATH_IN_SET("/bin", "/foo/bar", "/bin"));
98 assert_se(PATH_IN_SET("/", "/", "/", "/foo/bar"));
99 assert_se(!PATH_IN_SET("/", "/abc", "/def"));
101 assert_se(path_equal_ptr(NULL
, NULL
));
102 assert_se(path_equal_ptr("/a", "/a"));
103 assert_se(!path_equal_ptr("/a", "/b"));
104 assert_se(!path_equal_ptr("/a", NULL
));
105 assert_se(!path_equal_ptr(NULL
, "/a"));
108 static void test_path_equal_root(void) {
109 /* Nail down the details of how path_equal("/", ...) works. */
111 assert_se(path_equal("/", "/"));
112 assert_se(path_equal("/", "//"));
114 assert_se(!path_equal("/", "/./"));
115 assert_se(!path_equal("/", "/../"));
117 assert_se(!path_equal("/", "/.../"));
119 /* Make sure that files_same works as expected. */
121 assert_se(files_same("/", "/", 0) > 0);
122 assert_se(files_same("/", "/", AT_SYMLINK_NOFOLLOW
) > 0);
123 assert_se(files_same("/", "//", 0) > 0);
124 assert_se(files_same("/", "//", AT_SYMLINK_NOFOLLOW
) > 0);
126 assert_se(files_same("/", "/./", 0) > 0);
127 assert_se(files_same("/", "/./", AT_SYMLINK_NOFOLLOW
) > 0);
128 assert_se(files_same("/", "/../", 0) > 0);
129 assert_se(files_same("/", "/../", AT_SYMLINK_NOFOLLOW
) > 0);
131 assert_se(files_same("/", "/.../", 0) == -ENOENT
);
132 assert_se(files_same("/", "/.../", AT_SYMLINK_NOFOLLOW
) == -ENOENT
);
134 /* The same for path_equal_or_files_same. */
136 assert_se(path_equal_or_files_same("/", "/", 0));
137 assert_se(path_equal_or_files_same("/", "/", AT_SYMLINK_NOFOLLOW
));
138 assert_se(path_equal_or_files_same("/", "//", 0));
139 assert_se(path_equal_or_files_same("/", "//", AT_SYMLINK_NOFOLLOW
));
141 assert_se(path_equal_or_files_same("/", "/./", 0));
142 assert_se(path_equal_or_files_same("/", "/./", AT_SYMLINK_NOFOLLOW
));
143 assert_se(path_equal_or_files_same("/", "/../", 0));
144 assert_se(path_equal_or_files_same("/", "/../", AT_SYMLINK_NOFOLLOW
));
146 assert_se(!path_equal_or_files_same("/", "/.../", 0));
147 assert_se(!path_equal_or_files_same("/", "/.../", AT_SYMLINK_NOFOLLOW
));
150 static void test_find_binary(const char *self
) {
153 assert_se(find_binary("/bin/sh", &p
) == 0);
155 assert_se(path_equal(p
, "/bin/sh"));
158 assert_se(find_binary(self
, &p
) == 0);
160 /* libtool might prefix the binary name with "lt-" */
161 assert_se(endswith(p
, "/lt-test-path-util") || endswith(p
, "/test-path-util"));
162 assert_se(path_is_absolute(p
));
165 assert_se(find_binary("sh", &p
) == 0);
167 assert_se(endswith(p
, "/sh"));
168 assert_se(path_is_absolute(p
));
171 assert_se(find_binary("xxxx-xxxx", &p
) == -ENOENT
);
172 assert_se(find_binary("/some/dir/xxxx-xxxx", &p
) == -ENOENT
);
175 static void test_prefixes(void) {
176 static const char* values
[] = { "/a/b/c/d", "/a/b/c", "/a/b", "/a", "", NULL
};
182 PATH_FOREACH_PREFIX_MORE(s
, "/a/b/c/d") {
183 log_error("---%s---", s
);
184 assert_se(streq(s
, values
[i
++]));
186 assert_se(values
[i
] == NULL
);
189 PATH_FOREACH_PREFIX(s
, "/a/b/c/d") {
190 log_error("---%s---", s
);
191 assert_se(streq(s
, values
[i
++]));
193 assert_se(values
[i
] == NULL
);
196 PATH_FOREACH_PREFIX_MORE(s
, "////a////b////c///d///////")
197 assert_se(streq(s
, values
[i
++]));
198 assert_se(values
[i
] == NULL
);
201 PATH_FOREACH_PREFIX(s
, "////a////b////c///d///////")
202 assert_se(streq(s
, values
[i
++]));
203 assert_se(values
[i
] == NULL
);
205 PATH_FOREACH_PREFIX(s
, "////")
206 assert_not_reached("Wut?");
209 PATH_FOREACH_PREFIX_MORE(s
, "////") {
211 assert_se(streq(s
, ""));
216 PATH_FOREACH_PREFIX(s
, "")
217 assert_not_reached("wut?");
220 PATH_FOREACH_PREFIX_MORE(s
, "") {
222 assert_se(streq(s
, ""));
227 static void test_path_join(void) {
229 #define test_join(root, path, rest, expected) { \
230 _cleanup_free_ char *z = NULL; \
231 z = path_join(root, path, rest); \
232 assert_se(streq(z, expected)); \
235 test_join("/root", "/a/b", "/c", "/root/a/b/c");
236 test_join("/root", "a/b", "c", "/root/a/b/c");
237 test_join("/root", "/a/b", "c", "/root/a/b/c");
238 test_join("/root", "/", "c", "/root/c");
239 test_join("/root", "/", NULL
, "/root/");
241 test_join(NULL
, "/a/b", "/c", "/a/b/c");
242 test_join(NULL
, "a/b", "c", "a/b/c");
243 test_join(NULL
, "/a/b", "c", "/a/b/c");
244 test_join(NULL
, "/", "c", "/c");
245 test_join(NULL
, "/", NULL
, "/");
248 static void test_fsck_exists(void) {
249 /* Ensure we use a sane default for PATH. */
252 /* fsck.minix is provided by util-linux and will probably exist. */
253 assert_se(fsck_exists("minix") == 1);
255 assert_se(fsck_exists("AbCdE") == 0);
256 assert_se(fsck_exists("/../bin/") == 0);
259 static void test_make_relative(void) {
262 assert_se(path_make_relative("some/relative/path", "/some/path", &result
) < 0);
263 assert_se(path_make_relative("/some/path", "some/relative/path", &result
) < 0);
264 assert_se(path_make_relative("/some/dotdot/../path", "/some/path", &result
) < 0);
266 #define test(from_dir, to_path, expected) { \
267 _cleanup_free_ char *z = NULL; \
268 path_make_relative(from_dir, to_path, &z); \
269 assert_se(streq(z, expected)); \
273 test("/", "/some/path", "some/path");
274 test("/some/path", "/some/path", ".");
275 test("/some/path", "/some/path/in/subdir", "in/subdir");
276 test("/some/path", "/", "../..");
277 test("/some/path", "/some/other/path", "../other/path");
278 test("/some/path/./dot", "/some/further/path", "../../further/path");
279 test("//extra/////slashes///won't////fool///anybody//", "////extra///slashes////are/just///fine///", "../../../are/just/fine");
282 static void test_strv_resolve(void) {
283 char tmp_dir
[] = "/tmp/test-path-util-XXXXXX";
284 _cleanup_strv_free_
char **search_dirs
= NULL
;
285 _cleanup_strv_free_
char **absolute_dirs
= NULL
;
288 assert_se(mkdtemp(tmp_dir
) != NULL
);
290 search_dirs
= strv_new("/dir1", "/dir2", "/dir3", NULL
);
291 assert_se(search_dirs
);
292 STRV_FOREACH(d
, search_dirs
) {
293 char *p
= strappend(tmp_dir
, *d
);
295 assert_se(strv_push(&absolute_dirs
, p
) == 0);
298 assert_se(mkdir(absolute_dirs
[0], 0700) == 0);
299 assert_se(mkdir(absolute_dirs
[1], 0700) == 0);
300 assert_se(symlink("dir2", absolute_dirs
[2]) == 0);
302 path_strv_resolve(search_dirs
, tmp_dir
);
303 assert_se(streq(search_dirs
[0], "/dir1"));
304 assert_se(streq(search_dirs
[1], "/dir2"));
305 assert_se(streq(search_dirs
[2], "/dir2"));
307 assert_se(rm_rf(tmp_dir
, REMOVE_ROOT
|REMOVE_PHYSICAL
) == 0);
310 static void test_path_startswith(void) {
313 p
= path_startswith("/foo/bar/barfoo/", "/foo");
314 assert_se(streq_ptr(p
, "bar/barfoo/"));
316 p
= path_startswith("/foo/bar/barfoo/", "/foo/");
317 assert_se(streq_ptr(p
, "bar/barfoo/"));
319 p
= path_startswith("/foo/bar/barfoo/", "/");
320 assert_se(streq_ptr(p
, "foo/bar/barfoo/"));
322 p
= path_startswith("/foo/bar/barfoo/", "////");
323 assert_se(streq_ptr(p
, "foo/bar/barfoo/"));
325 p
= path_startswith("/foo/bar/barfoo/", "/foo//bar/////barfoo///");
326 assert_se(streq_ptr(p
, ""));
328 p
= path_startswith("/foo/bar/barfoo/", "/foo/bar/barfoo////");
329 assert_se(streq_ptr(p
, ""));
331 p
= path_startswith("/foo/bar/barfoo/", "/foo/bar///barfoo/");
332 assert_se(streq_ptr(p
, ""));
334 p
= path_startswith("/foo/bar/barfoo/", "/foo////bar/barfoo/");
335 assert_se(streq_ptr(p
, ""));
337 p
= path_startswith("/foo/bar/barfoo/", "////foo/bar/barfoo/");
338 assert_se(streq_ptr(p
, ""));
340 p
= path_startswith("/foo/bar/barfoo/", "/foo/bar/barfoo");
341 assert_se(streq_ptr(p
, ""));
343 assert_se(!path_startswith("/foo/bar/barfoo/", "/foo/bar/barfooa/"));
344 assert_se(!path_startswith("/foo/bar/barfoo/", "/foo/bar/barfooa"));
345 assert_se(!path_startswith("/foo/bar/barfoo/", ""));
346 assert_se(!path_startswith("/foo/bar/barfoo/", "/bar/foo"));
347 assert_se(!path_startswith("/foo/bar/barfoo/", "/f/b/b/"));
350 static void test_prefix_root_one(const char *r
, const char *p
, const char *expected
) {
351 _cleanup_free_
char *s
= NULL
;
354 assert_se(s
= prefix_root(r
, p
));
355 assert_se(streq_ptr(s
, expected
));
357 t
= prefix_roota(r
, p
);
359 assert_se(streq_ptr(t
, expected
));
362 static void test_prefix_root(void) {
363 test_prefix_root_one("/", "/foo", "/foo");
364 test_prefix_root_one(NULL
, "/foo", "/foo");
365 test_prefix_root_one("", "/foo", "/foo");
366 test_prefix_root_one("///", "/foo", "/foo");
367 test_prefix_root_one("/", "////foo", "/foo");
368 test_prefix_root_one(NULL
, "////foo", "/foo");
370 test_prefix_root_one("/foo", "/bar", "/foo/bar");
371 test_prefix_root_one("/foo", "bar", "/foo/bar");
372 test_prefix_root_one("foo", "bar", "foo/bar");
373 test_prefix_root_one("/foo/", "/bar", "/foo/bar");
374 test_prefix_root_one("/foo/", "//bar", "/foo/bar");
375 test_prefix_root_one("/foo///", "//bar", "/foo/bar");
378 static void test_file_in_same_dir(void) {
381 t
= file_in_same_dir("/", "a");
382 assert_se(streq(t
, "/a"));
385 t
= file_in_same_dir("/", "/a");
386 assert_se(streq(t
, "/a"));
389 t
= file_in_same_dir("", "a");
390 assert_se(streq(t
, "a"));
393 t
= file_in_same_dir("a/", "a");
394 assert_se(streq(t
, "a/a"));
397 t
= file_in_same_dir("bar/foo", "bar");
398 assert_se(streq(t
, "bar/bar"));
402 static void test_last_path_component(void) {
403 assert_se(streq(last_path_component("a/b/c"), "c"));
404 assert_se(streq(last_path_component("a/b/c/"), "c/"));
405 assert_se(streq(last_path_component("/"), "/"));
406 assert_se(streq(last_path_component("//"), "/"));
407 assert_se(streq(last_path_component("///"), "/"));
408 assert_se(streq(last_path_component("."), "."));
409 assert_se(streq(last_path_component("./."), "."));
410 assert_se(streq(last_path_component("././"), "./"));
411 assert_se(streq(last_path_component("././/"), ".//"));
412 assert_se(streq(last_path_component("/foo/a"), "a"));
413 assert_se(streq(last_path_component("/foo/a/"), "a/"));
414 assert_se(streq(last_path_component(""), ""));
417 static void test_filename_is_valid(void) {
418 char foo
[FILENAME_MAX
+2];
421 assert_se(!filename_is_valid(""));
422 assert_se(!filename_is_valid("/bar/foo"));
423 assert_se(!filename_is_valid("/"));
424 assert_se(!filename_is_valid("."));
425 assert_se(!filename_is_valid(".."));
427 for (i
=0; i
<FILENAME_MAX
+1; i
++)
429 foo
[FILENAME_MAX
+1] = '\0';
431 assert_se(!filename_is_valid(foo
));
433 assert_se(filename_is_valid("foo_bar-333"));
434 assert_se(filename_is_valid("o.o"));
437 static void test_hidden_or_backup_file(void) {
438 assert_se(hidden_or_backup_file(".hidden"));
439 assert_se(hidden_or_backup_file("..hidden"));
440 assert_se(!hidden_or_backup_file("hidden."));
442 assert_se(hidden_or_backup_file("backup~"));
443 assert_se(hidden_or_backup_file(".backup~"));
445 assert_se(hidden_or_backup_file("lost+found"));
446 assert_se(hidden_or_backup_file("aquota.user"));
447 assert_se(hidden_or_backup_file("aquota.group"));
449 assert_se(hidden_or_backup_file("test.rpmnew"));
450 assert_se(hidden_or_backup_file("test.dpkg-old"));
451 assert_se(hidden_or_backup_file("test.dpkg-remove"));
452 assert_se(hidden_or_backup_file("test.swp"));
454 assert_se(!hidden_or_backup_file("test.rpmnew."));
455 assert_se(!hidden_or_backup_file("test.dpkg-old.foo"));
458 static void test_systemd_installation_has_version(const char *path
) {
460 const unsigned versions
[] = {0, 231, atoi(PACKAGE_VERSION
), 999};
463 for (i
= 0; i
< ELEMENTSOF(versions
); i
++) {
464 r
= systemd_installation_has_version(path
, versions
[i
]);
466 log_info("%s has systemd >= %u: %s",
467 path
?: "Current installation", versions
[i
], yes_no(r
));
471 static void test_skip_dev_prefix(void) {
473 assert_se(streq(skip_dev_prefix("/"), "/"));
474 assert_se(streq(skip_dev_prefix("/dev"), ""));
475 assert_se(streq(skip_dev_prefix("/dev/"), ""));
476 assert_se(streq(skip_dev_prefix("/dev/foo"), "foo"));
477 assert_se(streq(skip_dev_prefix("/dev/foo/bar"), "foo/bar"));
478 assert_se(streq(skip_dev_prefix("//dev"), ""));
479 assert_se(streq(skip_dev_prefix("//dev//"), ""));
480 assert_se(streq(skip_dev_prefix("/dev///foo"), "foo"));
481 assert_se(streq(skip_dev_prefix("///dev///foo///bar"), "foo///bar"));
482 assert_se(streq(skip_dev_prefix("//foo"), "//foo"));
483 assert_se(streq(skip_dev_prefix("foo"), "foo"));
486 int main(int argc
, char **argv
) {
487 log_set_max_level(LOG_DEBUG
);
488 log_parse_environment();
492 test_path_equal_root();
493 test_find_binary(argv
[0]);
497 test_make_relative();
499 test_path_startswith();
501 test_file_in_same_dir();
502 test_last_path_component();
503 test_filename_is_valid();
504 test_hidden_or_backup_file();
505 test_skip_dev_prefix();
507 test_systemd_installation_has_version(argv
[1]); /* NULL is OK */