]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/test/test-path-util.c
util-lib: move fstab_node_to_udev_node() to fstab-util.[ch]
[thirdparty/systemd.git] / src / test / test-path-util.c
CommitLineData
76877b46
ZJS
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2013 Zbigniew Jędrzejewski-Szmek
7
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.
12
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.
17
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/>.
20***/
21
a696dbef 22#include <stdio.h>
5d409034 23#include <sys/mount.h>
07630cea 24#include <unistd.h>
a696dbef 25
3ffd4af2 26#include "fd-util.h"
76877b46 27#include "macro.h"
07630cea 28#include "path-util.h"
c6878637 29#include "rm-rf.h"
07630cea
LP
30#include "string-util.h"
31#include "strv.h"
32#include "util.h"
76877b46 33
2230852b
MS
34#define test_path_compare(a, b, result) { \
35 assert_se(path_compare(a, b) == result); \
36 assert_se(path_compare(b, a) == -result); \
37 assert_se(path_equal(a, b) == !result); \
38 assert_se(path_equal(b, a) == !result); \
39 }
76877b46
ZJS
40
41static void test_path(void) {
3f72b427
LP
42 _cleanup_close_ int fd = -1;
43
2230852b
MS
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);
48 test_path_compare("goo/////", "goo", 0);
76877b46 49
2230852b
MS
50 test_path_compare("/goo/boo", "/goo//boo", 0);
51 test_path_compare("//goo/boo", "/goo/boo//", 0);
76877b46 52
2230852b 53 test_path_compare("/", "///", 0);
76877b46 54
2230852b
MS
55 test_path_compare("/x", "x/", 1);
56 test_path_compare("x/", "/", -1);
76877b46 57
2230852b
MS
58 test_path_compare("/x/./y", "x/y", 1);
59 test_path_compare("x/.y", "x/y", -1);
60
61 test_path_compare("foo", "/foo", -1);
62 test_path_compare("/foo", "/foo/bar", -1);
63 test_path_compare("/foo/aaa", "/foo/b", -1);
64 test_path_compare("/foo/aaa", "/foo/b/a", -1);
65 test_path_compare("/foo/a", "/foo/aaa", -1);
66 test_path_compare("/foo/a/b", "/foo/aaa", -1);
76877b46
ZJS
67
68 assert_se(path_is_absolute("/"));
69 assert_se(!path_is_absolute("./"));
70
71 assert_se(is_path("/dir"));
72 assert_se(is_path("a/b"));
73 assert_se(!is_path("."));
74
2b6bf07d
ZJS
75 assert_se(streq(basename("./aa/bb/../file.da."), "file.da."));
76 assert_se(streq(basename("/aa///.file"), ".file"));
77 assert_se(streq(basename("/aa///file..."), "file..."));
78 assert_se(streq(basename("file.../"), ""));
76877b46 79
3f72b427
LP
80 fd = open("/", O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOCTTY);
81 assert_se(fd >= 0);
5d409034 82 assert_se(fd_is_mount_point(fd, "/", 0) > 0);
76877b46
ZJS
83
84 {
85 char p1[] = "aaa/bbb////ccc";
86 char p2[] = "//aaa/.////ccc";
87 char p3[] = "/./";
88
8d95631e
FB
89 assert_se(path_equal(path_kill_slashes(p1), "aaa/bbb/ccc"));
90 assert_se(path_equal(path_kill_slashes(p2), "/aaa/./ccc"));
91 assert_se(path_equal(path_kill_slashes(p3), "/./"));
76877b46
ZJS
92 }
93}
94
85eca92e 95static void test_find_binary(const char *self) {
c9d954b2
ZJS
96 char *p;
97
85eca92e 98 assert_se(find_binary("/bin/sh", &p) == 0);
c9d954b2 99 puts(p);
85eca92e 100 assert_se(path_equal(p, "/bin/sh"));
c9d954b2
ZJS
101 free(p);
102
85eca92e 103 assert_se(find_binary(self, &p) == 0);
c9d954b2 104 puts(p);
8d95631e
FB
105 assert_se(endswith(p, "/test-path-util"));
106 assert_se(path_is_absolute(p));
c9d954b2
ZJS
107 free(p);
108
85eca92e 109 assert_se(find_binary("sh", &p) == 0);
c9d954b2 110 puts(p);
8d95631e
FB
111 assert_se(endswith(p, "/sh"));
112 assert_se(path_is_absolute(p));
c9d954b2
ZJS
113 free(p);
114
85eca92e
LP
115 assert_se(find_binary("xxxx-xxxx", &p) == -ENOENT);
116 assert_se(find_binary("/some/dir/xxxx-xxxx", &p) == -ENOENT);
c9d954b2
ZJS
117}
118
fecffe5d 119static void test_prefixes(void) {
e203f7c3
LP
120 static const char* values[] = { "/a/b/c/d", "/a/b/c", "/a/b", "/a", "", NULL};
121 unsigned i;
fecffe5d 122 char s[PATH_MAX];
e203f7c3 123 bool b;
fecffe5d 124
e203f7c3
LP
125 i = 0;
126 PATH_FOREACH_PREFIX_MORE(s, "/a/b/c/d") {
fecffe5d
LP
127 log_error("---%s---", s);
128 assert_se(streq(s, values[i++]));
129 }
e203f7c3 130 assert_se(values[i] == NULL);
fecffe5d 131
e203f7c3
LP
132 i = 1;
133 PATH_FOREACH_PREFIX(s, "/a/b/c/d") {
134 log_error("---%s---", s);
135 assert_se(streq(s, values[i++]));
136 }
fecffe5d
LP
137 assert_se(values[i] == NULL);
138
139 i = 0;
e203f7c3 140 PATH_FOREACH_PREFIX_MORE(s, "////a////b////c///d///////")
fecffe5d 141 assert_se(streq(s, values[i++]));
e203f7c3 142 assert_se(values[i] == NULL);
fecffe5d 143
e203f7c3
LP
144 i = 1;
145 PATH_FOREACH_PREFIX(s, "////a////b////c///d///////")
146 assert_se(streq(s, values[i++]));
fecffe5d
LP
147 assert_se(values[i] == NULL);
148
149 PATH_FOREACH_PREFIX(s, "////")
e203f7c3
LP
150 assert_not_reached("Wut?");
151
152 b = false;
153 PATH_FOREACH_PREFIX_MORE(s, "////") {
154 assert_se(!b);
fecffe5d 155 assert_se(streq(s, ""));
e203f7c3
LP
156 b = true;
157 }
158 assert_se(b);
fecffe5d
LP
159
160 PATH_FOREACH_PREFIX(s, "")
161 assert_not_reached("wut?");
162
e203f7c3
LP
163 b = false;
164 PATH_FOREACH_PREFIX_MORE(s, "") {
8d95631e
FB
165 assert_se(!b);
166 assert_se(streq(s, ""));
e203f7c3
LP
167 b = true;
168 }
fecffe5d
LP
169}
170
0c6ea3a4 171static void test_path_join(void) {
59ae3a95
TA
172
173#define test_join(root, path, rest, expected) { \
174 _cleanup_free_ char *z = NULL; \
175 z = path_join(root, path, rest); \
176 assert_se(streq(z, expected)); \
177 }
178
179 test_join("/root", "/a/b", "/c", "/root/a/b/c");
180 test_join("/root", "a/b", "c", "/root/a/b/c");
181 test_join("/root", "/a/b", "c", "/root/a/b/c");
bc854dc7 182 test_join("/root", "/", "c", "/root/c");
59ae3a95
TA
183 test_join("/root", "/", NULL, "/root/");
184
185 test_join(NULL, "/a/b", "/c", "/a/b/c");
186 test_join(NULL, "a/b", "c", "a/b/c");
187 test_join(NULL, "/a/b", "c", "/a/b/c");
bc854dc7 188 test_join(NULL, "/", "c", "/c");
59ae3a95 189 test_join(NULL, "/", NULL, "/");
0c6ea3a4
ZJS
190}
191
eb66db55
MG
192static void test_fsck_exists(void) {
193 /* Ensure we use a sane default for PATH. */
194 unsetenv("PATH");
195
196 /* fsck.minix is provided by util-linux and will probably exist. */
85eca92e 197 assert_se(fsck_exists("minix") == 1);
eb66db55 198
85eca92e
LP
199 assert_se(fsck_exists("AbCdE") == 0);
200 assert_se(fsck_exists("/../bin/") == 0);
eb66db55
MG
201}
202
6b56a651
TK
203static void test_make_relative(void) {
204 char *result;
205
206 assert_se(path_make_relative("some/relative/path", "/some/path", &result) < 0);
207 assert_se(path_make_relative("/some/path", "some/relative/path", &result) < 0);
208
59ae3a95
TA
209#define test(from_dir, to_path, expected) { \
210 _cleanup_free_ char *z = NULL; \
211 path_make_relative(from_dir, to_path, &z); \
212 assert_se(streq(z, expected)); \
6b56a651
TK
213 }
214
215 test("/", "/", ".");
216 test("/", "/some/path", "some/path");
217 test("/some/path", "/some/path", ".");
218 test("/some/path", "/some/path/in/subdir", "in/subdir");
219 test("/some/path", "/", "../..");
220 test("/some/path", "/some/other/path", "../other/path");
221 test("//extra/////slashes///won't////fool///anybody//", "////extra///slashes////are/just///fine///", "../../../are/just/fine");
222}
223
3e8a78c8
MM
224static void test_strv_resolve(void) {
225 char tmp_dir[] = "/tmp/test-path-util-XXXXXX";
226 _cleanup_strv_free_ char **search_dirs = NULL;
227 _cleanup_strv_free_ char **absolute_dirs = NULL;
228 char **d;
229
230 assert_se(mkdtemp(tmp_dir) != NULL);
231
232 search_dirs = strv_new("/dir1", "/dir2", "/dir3", NULL);
233 assert_se(search_dirs);
234 STRV_FOREACH(d, search_dirs) {
235 char *p = strappend(tmp_dir, *d);
236 assert_se(p);
237 assert_se(strv_push(&absolute_dirs, p) == 0);
238 }
239
240 assert_se(mkdir(absolute_dirs[0], 0700) == 0);
241 assert_se(mkdir(absolute_dirs[1], 0700) == 0);
242 assert_se(symlink("dir2", absolute_dirs[2]) == 0);
243
244 path_strv_resolve(search_dirs, tmp_dir);
245 assert_se(streq(search_dirs[0], "/dir1"));
246 assert_se(streq(search_dirs[1], "/dir2"));
247 assert_se(streq(search_dirs[2], "/dir2"));
248
c6878637 249 assert_se(rm_rf(tmp_dir, REMOVE_ROOT|REMOVE_PHYSICAL) == 0);
3e8a78c8
MM
250}
251
5895b62f
RC
252static void test_path_startswith(void) {
253 assert_se(path_startswith("/foo/bar/barfoo/", "/foo"));
254 assert_se(path_startswith("/foo/bar/barfoo/", "/foo/"));
255 assert_se(path_startswith("/foo/bar/barfoo/", "/"));
256 assert_se(path_startswith("/foo/bar/barfoo/", "////"));
257 assert_se(path_startswith("/foo/bar/barfoo/", "/foo//bar/////barfoo///"));
258 assert_se(path_startswith("/foo/bar/barfoo/", "/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
264 assert_se(!path_startswith("/foo/bar/barfoo/", "/foo/bar/barfooa/"));
265 assert_se(!path_startswith("/foo/bar/barfoo/", "/foo/bar/barfooa"));
266 assert_se(!path_startswith("/foo/bar/barfoo/", ""));
267 assert_se(!path_startswith("/foo/bar/barfoo/", "/bar/foo"));
268 assert_se(!path_startswith("/foo/bar/barfoo/", "/f/b/b/"));
269}
270
1d13f648
LP
271static void test_prefix_root_one(const char *r, const char *p, const char *expected) {
272 _cleanup_free_ char *s = NULL;
273 const char *t;
274
275 assert_se(s = prefix_root(r, p));
276 assert_se(streq_ptr(s, expected));
277
278 t = prefix_roota(r, p);
279 assert_se(t);
280 assert_se(streq_ptr(t, expected));
281}
282
283static void test_prefix_root(void) {
284 test_prefix_root_one("/", "/foo", "/foo");
285 test_prefix_root_one(NULL, "/foo", "/foo");
286 test_prefix_root_one("", "/foo", "/foo");
287 test_prefix_root_one("///", "/foo", "/foo");
288 test_prefix_root_one("/", "////foo", "/foo");
289 test_prefix_root_one(NULL, "////foo", "/foo");
290
291 test_prefix_root_one("/foo", "/bar", "/foo/bar");
292 test_prefix_root_one("/foo", "bar", "/foo/bar");
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}
298
5d409034 299static void test_path_is_mount_point(void) {
36908eb8 300 int fd;
5d409034
MP
301 char tmp_dir[] = "/tmp/test-path-is-mount-point-XXXXXX";
302 _cleanup_free_ char *file1 = NULL, *file2 = NULL, *link1 = NULL, *link2 = NULL;
36908eb8
MP
303 _cleanup_free_ char *dir1 = NULL, *dir1file = NULL, *dirlink1 = NULL, *dirlink1file = NULL;
304 _cleanup_free_ char *dir2 = NULL, *dir2file = NULL;
5d409034 305
e26d6ce5
MP
306 assert_se(path_is_mount_point("/", AT_SYMLINK_FOLLOW) > 0);
307 assert_se(path_is_mount_point("/", 0) > 0);
5d409034 308
e26d6ce5
MP
309 assert_se(path_is_mount_point("/proc", AT_SYMLINK_FOLLOW) > 0);
310 assert_se(path_is_mount_point("/proc", 0) > 0);
5d409034 311
e26d6ce5
MP
312 assert_se(path_is_mount_point("/proc/1", AT_SYMLINK_FOLLOW) == 0);
313 assert_se(path_is_mount_point("/proc/1", 0) == 0);
5d409034 314
e26d6ce5
MP
315 assert_se(path_is_mount_point("/sys", AT_SYMLINK_FOLLOW) > 0);
316 assert_se(path_is_mount_point("/sys", 0) > 0);
5d409034 317
36908eb8
MP
318 /* we'll create a hierarchy of different kinds of dir/file/link
319 * layouts:
320 *
321 * <tmp>/file1, <tmp>/file2
322 * <tmp>/link1 -> file1, <tmp>/link2 -> file2
323 * <tmp>/dir1/
324 * <tmp>/dir1/file
325 * <tmp>/dirlink1 -> dir1
326 * <tmp>/dirlink1file -> dirlink1/file
327 * <tmp>/dir2/
328 * <tmp>/dir2/file
329 */
330
5d409034
MP
331 /* file mountpoints */
332 assert_se(mkdtemp(tmp_dir) != NULL);
333 file1 = path_join(NULL, tmp_dir, "file1");
334 assert_se(file1);
335 file2 = path_join(NULL, tmp_dir, "file2");
336 assert_se(file2);
337 fd = open(file1, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0664);
338 assert_se(fd > 0);
339 close(fd);
340 fd = open(file2, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0664);
341 assert_se(fd > 0);
342 close(fd);
343 link1 = path_join(NULL, tmp_dir, "link1");
344 assert_se(link1);
345 assert_se(symlink("file1", link1) == 0);
346 link2 = path_join(NULL, tmp_dir, "link2");
347 assert_se(link1);
348 assert_se(symlink("file2", link2) == 0);
349
e26d6ce5
MP
350 assert_se(path_is_mount_point(file1, AT_SYMLINK_FOLLOW) == 0);
351 assert_se(path_is_mount_point(file1, 0) == 0);
352 assert_se(path_is_mount_point(link1, AT_SYMLINK_FOLLOW) == 0);
353 assert_se(path_is_mount_point(link1, 0) == 0);
5d409034 354
36908eb8
MP
355 /* directory mountpoints */
356 dir1 = path_join(NULL, tmp_dir, "dir1");
357 assert_se(dir1);
358 assert_se(mkdir(dir1, 0755) == 0);
359 dirlink1 = path_join(NULL, tmp_dir, "dirlink1");
360 assert_se(dirlink1);
361 assert_se(symlink("dir1", dirlink1) == 0);
362 dirlink1file = path_join(NULL, tmp_dir, "dirlink1file");
363 assert_se(dirlink1file);
364 assert_se(symlink("dirlink1/file", dirlink1file) == 0);
365 dir2 = path_join(NULL, tmp_dir, "dir2");
366 assert_se(dir2);
367 assert_se(mkdir(dir2, 0755) == 0);
368
369 assert_se(path_is_mount_point(dir1, AT_SYMLINK_FOLLOW) == 0);
370 assert_se(path_is_mount_point(dir1, 0) == 0);
371 assert_se(path_is_mount_point(dirlink1, AT_SYMLINK_FOLLOW) == 0);
372 assert_se(path_is_mount_point(dirlink1, 0) == 0);
373
374 /* file in subdirectory mountpoints */
375 dir1file = path_join(NULL, dir1, "file");
376 assert_se(dir1file);
377 fd = open(dir1file, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0664);
378 assert_se(fd > 0);
379 close(fd);
380
381 assert_se(path_is_mount_point(dir1file, AT_SYMLINK_FOLLOW) == 0);
382 assert_se(path_is_mount_point(dir1file, 0) == 0);
383 assert_se(path_is_mount_point(dirlink1file, AT_SYMLINK_FOLLOW) == 0);
384 assert_se(path_is_mount_point(dirlink1file, 0) == 0);
385
386 /* these tests will only work as root */
5d409034 387 if (mount(file1, file2, NULL, MS_BIND, NULL) >= 0) {
36908eb8
MP
388 int rt, rf, rlt, rlf, rl1t, rl1f;
389
390 /* files */
391 /* capture results in vars, to avoid dangling mounts on failure */
e26d6ce5
MP
392 rf = path_is_mount_point(file2, 0);
393 rt = path_is_mount_point(file2, AT_SYMLINK_FOLLOW);
394 rlf = path_is_mount_point(link2, 0);
395 rlt = path_is_mount_point(link2, AT_SYMLINK_FOLLOW);
5d409034
MP
396
397 assert_se(umount(file2) == 0);
398
399 assert_se(rf == 1);
400 assert_se(rt == 1);
401 assert_se(rlf == 0);
402 assert_se(rlt == 1);
36908eb8
MP
403
404 /* dirs */
405 dir2file = path_join(NULL, dir2, "file");
406 assert_se(dir2file);
407 fd = open(dir2file, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0664);
408 assert_se(fd > 0);
409 close(fd);
410
411 assert_se(mount(dir2, dir1, NULL, MS_BIND, NULL) >= 0);
412
413 rf = path_is_mount_point(dir1, 0);
414 rt = path_is_mount_point(dir1, AT_SYMLINK_FOLLOW);
415 rlf = path_is_mount_point(dirlink1, 0);
416 rlt = path_is_mount_point(dirlink1, AT_SYMLINK_FOLLOW);
417 /* its parent is a mount point, but not /file itself */
418 rl1f = path_is_mount_point(dirlink1file, 0);
419 rl1t = path_is_mount_point(dirlink1file, AT_SYMLINK_FOLLOW);
420
421 assert_se(umount(dir1) == 0);
422
423 assert_se(rf == 1);
424 assert_se(rt == 1);
425 assert_se(rlf == 0);
426 assert_se(rlt == 1);
427 assert_se(rl1f == 0);
428 assert_se(rl1t == 0);
429
5d409034
MP
430 } else
431 printf("Skipping bind mount file test: %m\n");
432
433 assert_se(rm_rf(tmp_dir, REMOVE_ROOT|REMOVE_PHYSICAL) == 0);
434}
435
7f076504 436int main(int argc, char **argv) {
76877b46 437 test_path();
85eca92e 438 test_find_binary(argv[0]);
fecffe5d 439 test_prefixes();
0c6ea3a4 440 test_path_join();
eb66db55 441 test_fsck_exists();
6b56a651 442 test_make_relative();
3e8a78c8 443 test_strv_resolve();
5895b62f 444 test_path_startswith();
1d13f648 445 test_prefix_root();
5d409034 446 test_path_is_mount_point();
5895b62f 447
76877b46
ZJS
448 return 0;
449}