]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/test/test-path-util.c
Merge pull request #121 from martinpitt/master
[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>
3e8a78c8 23#include <unistd.h>
5d409034 24#include <sys/mount.h>
a696dbef 25
76877b46
ZJS
26#include "path-util.h"
27#include "util.h"
28#include "macro.h"
3e8a78c8 29#include "strv.h"
c6878637 30#include "rm-rf.h"
76877b46 31
2230852b
MS
32#define test_path_compare(a, b, result) { \
33 assert_se(path_compare(a, b) == result); \
34 assert_se(path_compare(b, a) == -result); \
35 assert_se(path_equal(a, b) == !result); \
36 assert_se(path_equal(b, a) == !result); \
37 }
76877b46
ZJS
38
39static void test_path(void) {
3f72b427
LP
40 _cleanup_close_ int fd = -1;
41
2230852b
MS
42 test_path_compare("/goo", "/goo", 0);
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);
76877b46 47
2230852b
MS
48 test_path_compare("/goo/boo", "/goo//boo", 0);
49 test_path_compare("//goo/boo", "/goo/boo//", 0);
76877b46 50
2230852b 51 test_path_compare("/", "///", 0);
76877b46 52
2230852b
MS
53 test_path_compare("/x", "x/", 1);
54 test_path_compare("x/", "/", -1);
76877b46 55
2230852b
MS
56 test_path_compare("/x/./y", "x/y", 1);
57 test_path_compare("x/.y", "x/y", -1);
58
59 test_path_compare("foo", "/foo", -1);
60 test_path_compare("/foo", "/foo/bar", -1);
61 test_path_compare("/foo/aaa", "/foo/b", -1);
62 test_path_compare("/foo/aaa", "/foo/b/a", -1);
63 test_path_compare("/foo/a", "/foo/aaa", -1);
64 test_path_compare("/foo/a/b", "/foo/aaa", -1);
76877b46
ZJS
65
66 assert_se(path_is_absolute("/"));
67 assert_se(!path_is_absolute("./"));
68
69 assert_se(is_path("/dir"));
70 assert_se(is_path("a/b"));
71 assert_se(!is_path("."));
72
2b6bf07d
ZJS
73 assert_se(streq(basename("./aa/bb/../file.da."), "file.da."));
74 assert_se(streq(basename("/aa///.file"), ".file"));
75 assert_se(streq(basename("/aa///file..."), "file..."));
76 assert_se(streq(basename("file.../"), ""));
76877b46 77
a696dbef 78#define test_parent(x, y) { \
c8b32e11 79 _cleanup_free_ char *z = NULL; \
a696dbef
ZJS
80 int r = path_get_parent(x, &z); \
81 printf("expected: %s\n", y ? y : "error"); \
82 printf("actual: %s\n", r<0 ? "error" : z); \
83 assert_se((y==NULL) ^ (r==0)); \
84 assert_se(y==NULL || path_equal(z, y)); \
76877b46
ZJS
85 }
86
87 test_parent("./aa/bb/../file.da.", "./aa/bb/..");
88 test_parent("/aa///.file", "/aa///");
89 test_parent("/aa///file...", "/aa///");
a696dbef 90 test_parent("file.../", NULL);
76877b46 91
3f72b427
LP
92 fd = open("/", O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOCTTY);
93 assert_se(fd >= 0);
5d409034 94 assert_se(fd_is_mount_point(fd, "/", 0) > 0);
76877b46
ZJS
95
96 {
97 char p1[] = "aaa/bbb////ccc";
98 char p2[] = "//aaa/.////ccc";
99 char p3[] = "/./";
100
8d95631e
FB
101 assert_se(path_equal(path_kill_slashes(p1), "aaa/bbb/ccc"));
102 assert_se(path_equal(path_kill_slashes(p2), "/aaa/./ccc"));
103 assert_se(path_equal(path_kill_slashes(p3), "/./"));
76877b46
ZJS
104 }
105}
106
b63bd109 107static void test_find_binary(const char *self, bool local) {
c9d954b2
ZJS
108 char *p;
109
b63bd109 110 assert_se(find_binary("/bin/sh", local, &p) == 0);
c9d954b2 111 puts(p);
8d95631e 112 assert_se(streq(p, "/bin/sh"));
c9d954b2
ZJS
113 free(p);
114
b63bd109 115 assert_se(find_binary(self, local, &p) == 0);
c9d954b2 116 puts(p);
8d95631e
FB
117 assert_se(endswith(p, "/test-path-util"));
118 assert_se(path_is_absolute(p));
c9d954b2
ZJS
119 free(p);
120
b63bd109 121 assert_se(find_binary("sh", local, &p) == 0);
c9d954b2 122 puts(p);
8d95631e
FB
123 assert_se(endswith(p, "/sh"));
124 assert_se(path_is_absolute(p));
c9d954b2
ZJS
125 free(p);
126
b63bd109 127 assert_se(find_binary("xxxx-xxxx", local, &p) == -ENOENT);
b972115c 128
b63bd109
ZJS
129 assert_se(find_binary("/some/dir/xxxx-xxxx", local, &p) ==
130 (local ? -ENOENT : 0));
f08c4c08
TA
131 if (!local)
132 free(p);
c9d954b2
ZJS
133}
134
fecffe5d 135static void test_prefixes(void) {
e203f7c3
LP
136 static const char* values[] = { "/a/b/c/d", "/a/b/c", "/a/b", "/a", "", NULL};
137 unsigned i;
fecffe5d 138 char s[PATH_MAX];
e203f7c3 139 bool b;
fecffe5d 140
e203f7c3
LP
141 i = 0;
142 PATH_FOREACH_PREFIX_MORE(s, "/a/b/c/d") {
fecffe5d
LP
143 log_error("---%s---", s);
144 assert_se(streq(s, values[i++]));
145 }
e203f7c3 146 assert_se(values[i] == NULL);
fecffe5d 147
e203f7c3
LP
148 i = 1;
149 PATH_FOREACH_PREFIX(s, "/a/b/c/d") {
150 log_error("---%s---", s);
151 assert_se(streq(s, values[i++]));
152 }
fecffe5d
LP
153 assert_se(values[i] == NULL);
154
155 i = 0;
e203f7c3 156 PATH_FOREACH_PREFIX_MORE(s, "////a////b////c///d///////")
fecffe5d 157 assert_se(streq(s, values[i++]));
e203f7c3 158 assert_se(values[i] == NULL);
fecffe5d 159
e203f7c3
LP
160 i = 1;
161 PATH_FOREACH_PREFIX(s, "////a////b////c///d///////")
162 assert_se(streq(s, values[i++]));
fecffe5d
LP
163 assert_se(values[i] == NULL);
164
165 PATH_FOREACH_PREFIX(s, "////")
e203f7c3
LP
166 assert_not_reached("Wut?");
167
168 b = false;
169 PATH_FOREACH_PREFIX_MORE(s, "////") {
170 assert_se(!b);
fecffe5d 171 assert_se(streq(s, ""));
e203f7c3
LP
172 b = true;
173 }
174 assert_se(b);
fecffe5d
LP
175
176 PATH_FOREACH_PREFIX(s, "")
177 assert_not_reached("wut?");
178
e203f7c3
LP
179 b = false;
180 PATH_FOREACH_PREFIX_MORE(s, "") {
8d95631e
FB
181 assert_se(!b);
182 assert_se(streq(s, ""));
e203f7c3
LP
183 b = true;
184 }
fecffe5d
LP
185}
186
0c6ea3a4 187static void test_path_join(void) {
59ae3a95
TA
188
189#define test_join(root, path, rest, expected) { \
190 _cleanup_free_ char *z = NULL; \
191 z = path_join(root, path, rest); \
192 assert_se(streq(z, expected)); \
193 }
194
195 test_join("/root", "/a/b", "/c", "/root/a/b/c");
196 test_join("/root", "a/b", "c", "/root/a/b/c");
197 test_join("/root", "/a/b", "c", "/root/a/b/c");
bc854dc7 198 test_join("/root", "/", "c", "/root/c");
59ae3a95
TA
199 test_join("/root", "/", NULL, "/root/");
200
201 test_join(NULL, "/a/b", "/c", "/a/b/c");
202 test_join(NULL, "a/b", "c", "a/b/c");
203 test_join(NULL, "/a/b", "c", "/a/b/c");
bc854dc7 204 test_join(NULL, "/", "c", "/c");
59ae3a95 205 test_join(NULL, "/", NULL, "/");
0c6ea3a4
ZJS
206}
207
eb66db55
MG
208static void test_fsck_exists(void) {
209 /* Ensure we use a sane default for PATH. */
210 unsetenv("PATH");
211
212 /* fsck.minix is provided by util-linux and will probably exist. */
213 assert_se(fsck_exists("minix") == 0);
214
215 assert_se(fsck_exists("AbCdE") == -ENOENT);
216}
217
6b56a651
TK
218static void test_make_relative(void) {
219 char *result;
220
221 assert_se(path_make_relative("some/relative/path", "/some/path", &result) < 0);
222 assert_se(path_make_relative("/some/path", "some/relative/path", &result) < 0);
223
59ae3a95
TA
224#define test(from_dir, to_path, expected) { \
225 _cleanup_free_ char *z = NULL; \
226 path_make_relative(from_dir, to_path, &z); \
227 assert_se(streq(z, expected)); \
6b56a651
TK
228 }
229
230 test("/", "/", ".");
231 test("/", "/some/path", "some/path");
232 test("/some/path", "/some/path", ".");
233 test("/some/path", "/some/path/in/subdir", "in/subdir");
234 test("/some/path", "/", "../..");
235 test("/some/path", "/some/other/path", "../other/path");
236 test("//extra/////slashes///won't////fool///anybody//", "////extra///slashes////are/just///fine///", "../../../are/just/fine");
237}
238
3e8a78c8
MM
239static void test_strv_resolve(void) {
240 char tmp_dir[] = "/tmp/test-path-util-XXXXXX";
241 _cleanup_strv_free_ char **search_dirs = NULL;
242 _cleanup_strv_free_ char **absolute_dirs = NULL;
243 char **d;
244
245 assert_se(mkdtemp(tmp_dir) != NULL);
246
247 search_dirs = strv_new("/dir1", "/dir2", "/dir3", NULL);
248 assert_se(search_dirs);
249 STRV_FOREACH(d, search_dirs) {
250 char *p = strappend(tmp_dir, *d);
251 assert_se(p);
252 assert_se(strv_push(&absolute_dirs, p) == 0);
253 }
254
255 assert_se(mkdir(absolute_dirs[0], 0700) == 0);
256 assert_se(mkdir(absolute_dirs[1], 0700) == 0);
257 assert_se(symlink("dir2", absolute_dirs[2]) == 0);
258
259 path_strv_resolve(search_dirs, tmp_dir);
260 assert_se(streq(search_dirs[0], "/dir1"));
261 assert_se(streq(search_dirs[1], "/dir2"));
262 assert_se(streq(search_dirs[2], "/dir2"));
263
c6878637 264 assert_se(rm_rf(tmp_dir, REMOVE_ROOT|REMOVE_PHYSICAL) == 0);
3e8a78c8
MM
265}
266
5895b62f
RC
267static void test_path_startswith(void) {
268 assert_se(path_startswith("/foo/bar/barfoo/", "/foo"));
269 assert_se(path_startswith("/foo/bar/barfoo/", "/foo/"));
270 assert_se(path_startswith("/foo/bar/barfoo/", "/"));
271 assert_se(path_startswith("/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/"));
276 assert_se(path_startswith("/foo/bar/barfoo/", "////foo/bar/barfoo/"));
277 assert_se(path_startswith("/foo/bar/barfoo/", "/foo/bar/barfoo"));
278
279 assert_se(!path_startswith("/foo/bar/barfoo/", "/foo/bar/barfooa/"));
280 assert_se(!path_startswith("/foo/bar/barfoo/", "/foo/bar/barfooa"));
281 assert_se(!path_startswith("/foo/bar/barfoo/", ""));
282 assert_se(!path_startswith("/foo/bar/barfoo/", "/bar/foo"));
283 assert_se(!path_startswith("/foo/bar/barfoo/", "/f/b/b/"));
284}
285
1d13f648
LP
286static void test_prefix_root_one(const char *r, const char *p, const char *expected) {
287 _cleanup_free_ char *s = NULL;
288 const char *t;
289
290 assert_se(s = prefix_root(r, p));
291 assert_se(streq_ptr(s, expected));
292
293 t = prefix_roota(r, p);
294 assert_se(t);
295 assert_se(streq_ptr(t, expected));
296}
297
298static void test_prefix_root(void) {
299 test_prefix_root_one("/", "/foo", "/foo");
300 test_prefix_root_one(NULL, "/foo", "/foo");
301 test_prefix_root_one("", "/foo", "/foo");
302 test_prefix_root_one("///", "/foo", "/foo");
303 test_prefix_root_one("/", "////foo", "/foo");
304 test_prefix_root_one(NULL, "////foo", "/foo");
305
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");
310 test_prefix_root_one("/foo/", "//bar", "/foo/bar");
311 test_prefix_root_one("/foo///", "//bar", "/foo/bar");
312}
313
5d409034
MP
314static void test_path_is_mount_point(void) {
315 int fd, rt, rf, rlt, rlf;
316 char tmp_dir[] = "/tmp/test-path-is-mount-point-XXXXXX";
317 _cleanup_free_ char *file1 = NULL, *file2 = NULL, *link1 = NULL, *link2 = NULL;
318
e26d6ce5
MP
319 assert_se(path_is_mount_point("/", AT_SYMLINK_FOLLOW) > 0);
320 assert_se(path_is_mount_point("/", 0) > 0);
5d409034 321
e26d6ce5
MP
322 assert_se(path_is_mount_point("/proc", AT_SYMLINK_FOLLOW) > 0);
323 assert_se(path_is_mount_point("/proc", 0) > 0);
5d409034 324
e26d6ce5
MP
325 assert_se(path_is_mount_point("/proc/1", AT_SYMLINK_FOLLOW) == 0);
326 assert_se(path_is_mount_point("/proc/1", 0) == 0);
5d409034 327
e26d6ce5
MP
328 assert_se(path_is_mount_point("/sys", AT_SYMLINK_FOLLOW) > 0);
329 assert_se(path_is_mount_point("/sys", 0) > 0);
5d409034
MP
330
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
MP
354
355 /* this test will only work as root */
356 if (mount(file1, file2, NULL, MS_BIND, NULL) >= 0) {
e26d6ce5
MP
357 rf = path_is_mount_point(file2, 0);
358 rt = path_is_mount_point(file2, AT_SYMLINK_FOLLOW);
359 rlf = path_is_mount_point(link2, 0);
360 rlt = path_is_mount_point(link2, AT_SYMLINK_FOLLOW);
5d409034
MP
361
362 assert_se(umount(file2) == 0);
363
364 assert_se(rf == 1);
365 assert_se(rt == 1);
366 assert_se(rlf == 0);
367 assert_se(rlt == 1);
368 } else
369 printf("Skipping bind mount file test: %m\n");
370
371 assert_se(rm_rf(tmp_dir, REMOVE_ROOT|REMOVE_PHYSICAL) == 0);
372}
373
7f076504 374int main(int argc, char **argv) {
76877b46 375 test_path();
b63bd109
ZJS
376 test_find_binary(argv[0], true);
377 test_find_binary(argv[0], false);
fecffe5d 378 test_prefixes();
0c6ea3a4 379 test_path_join();
eb66db55 380 test_fsck_exists();
6b56a651 381 test_make_relative();
3e8a78c8 382 test_strv_resolve();
5895b62f 383 test_path_startswith();
1d13f648 384 test_prefix_root();
5d409034 385 test_path_is_mount_point();
5895b62f 386
76877b46
ZJS
387 return 0;
388}