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