]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/test/test-path-util.c
Merge pull request #1664 from again4you/devel/tmp-smack_#5
[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 314static void test_path_is_mount_point(void) {
36908eb8 315 int fd;
5d409034
MP
316 char tmp_dir[] = "/tmp/test-path-is-mount-point-XXXXXX";
317 _cleanup_free_ char *file1 = NULL, *file2 = NULL, *link1 = NULL, *link2 = NULL;
36908eb8
MP
318 _cleanup_free_ char *dir1 = NULL, *dir1file = NULL, *dirlink1 = NULL, *dirlink1file = NULL;
319 _cleanup_free_ char *dir2 = NULL, *dir2file = NULL;
5d409034 320
e26d6ce5
MP
321 assert_se(path_is_mount_point("/", AT_SYMLINK_FOLLOW) > 0);
322 assert_se(path_is_mount_point("/", 0) > 0);
5d409034 323
e26d6ce5
MP
324 assert_se(path_is_mount_point("/proc", AT_SYMLINK_FOLLOW) > 0);
325 assert_se(path_is_mount_point("/proc", 0) > 0);
5d409034 326
e26d6ce5
MP
327 assert_se(path_is_mount_point("/proc/1", AT_SYMLINK_FOLLOW) == 0);
328 assert_se(path_is_mount_point("/proc/1", 0) == 0);
5d409034 329
e26d6ce5
MP
330 assert_se(path_is_mount_point("/sys", AT_SYMLINK_FOLLOW) > 0);
331 assert_se(path_is_mount_point("/sys", 0) > 0);
5d409034 332
36908eb8
MP
333 /* we'll create a hierarchy of different kinds of dir/file/link
334 * layouts:
335 *
336 * <tmp>/file1, <tmp>/file2
337 * <tmp>/link1 -> file1, <tmp>/link2 -> file2
338 * <tmp>/dir1/
339 * <tmp>/dir1/file
340 * <tmp>/dirlink1 -> dir1
341 * <tmp>/dirlink1file -> dirlink1/file
342 * <tmp>/dir2/
343 * <tmp>/dir2/file
344 */
345
5d409034
MP
346 /* file mountpoints */
347 assert_se(mkdtemp(tmp_dir) != NULL);
348 file1 = path_join(NULL, tmp_dir, "file1");
349 assert_se(file1);
350 file2 = path_join(NULL, tmp_dir, "file2");
351 assert_se(file2);
352 fd = open(file1, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0664);
353 assert_se(fd > 0);
354 close(fd);
355 fd = open(file2, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0664);
356 assert_se(fd > 0);
357 close(fd);
358 link1 = path_join(NULL, tmp_dir, "link1");
359 assert_se(link1);
360 assert_se(symlink("file1", link1) == 0);
361 link2 = path_join(NULL, tmp_dir, "link2");
362 assert_se(link1);
363 assert_se(symlink("file2", link2) == 0);
364
e26d6ce5
MP
365 assert_se(path_is_mount_point(file1, AT_SYMLINK_FOLLOW) == 0);
366 assert_se(path_is_mount_point(file1, 0) == 0);
367 assert_se(path_is_mount_point(link1, AT_SYMLINK_FOLLOW) == 0);
368 assert_se(path_is_mount_point(link1, 0) == 0);
5d409034 369
36908eb8
MP
370 /* directory mountpoints */
371 dir1 = path_join(NULL, tmp_dir, "dir1");
372 assert_se(dir1);
373 assert_se(mkdir(dir1, 0755) == 0);
374 dirlink1 = path_join(NULL, tmp_dir, "dirlink1");
375 assert_se(dirlink1);
376 assert_se(symlink("dir1", dirlink1) == 0);
377 dirlink1file = path_join(NULL, tmp_dir, "dirlink1file");
378 assert_se(dirlink1file);
379 assert_se(symlink("dirlink1/file", dirlink1file) == 0);
380 dir2 = path_join(NULL, tmp_dir, "dir2");
381 assert_se(dir2);
382 assert_se(mkdir(dir2, 0755) == 0);
383
384 assert_se(path_is_mount_point(dir1, AT_SYMLINK_FOLLOW) == 0);
385 assert_se(path_is_mount_point(dir1, 0) == 0);
386 assert_se(path_is_mount_point(dirlink1, AT_SYMLINK_FOLLOW) == 0);
387 assert_se(path_is_mount_point(dirlink1, 0) == 0);
388
389 /* file in subdirectory mountpoints */
390 dir1file = path_join(NULL, dir1, "file");
391 assert_se(dir1file);
392 fd = open(dir1file, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0664);
393 assert_se(fd > 0);
394 close(fd);
395
396 assert_se(path_is_mount_point(dir1file, AT_SYMLINK_FOLLOW) == 0);
397 assert_se(path_is_mount_point(dir1file, 0) == 0);
398 assert_se(path_is_mount_point(dirlink1file, AT_SYMLINK_FOLLOW) == 0);
399 assert_se(path_is_mount_point(dirlink1file, 0) == 0);
400
401 /* these tests will only work as root */
5d409034 402 if (mount(file1, file2, NULL, MS_BIND, NULL) >= 0) {
36908eb8
MP
403 int rt, rf, rlt, rlf, rl1t, rl1f;
404
405 /* files */
406 /* capture results in vars, to avoid dangling mounts on failure */
e26d6ce5
MP
407 rf = path_is_mount_point(file2, 0);
408 rt = path_is_mount_point(file2, AT_SYMLINK_FOLLOW);
409 rlf = path_is_mount_point(link2, 0);
410 rlt = path_is_mount_point(link2, AT_SYMLINK_FOLLOW);
5d409034
MP
411
412 assert_se(umount(file2) == 0);
413
414 assert_se(rf == 1);
415 assert_se(rt == 1);
416 assert_se(rlf == 0);
417 assert_se(rlt == 1);
36908eb8
MP
418
419 /* dirs */
420 dir2file = path_join(NULL, dir2, "file");
421 assert_se(dir2file);
422 fd = open(dir2file, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0664);
423 assert_se(fd > 0);
424 close(fd);
425
426 assert_se(mount(dir2, dir1, NULL, MS_BIND, NULL) >= 0);
427
428 rf = path_is_mount_point(dir1, 0);
429 rt = path_is_mount_point(dir1, AT_SYMLINK_FOLLOW);
430 rlf = path_is_mount_point(dirlink1, 0);
431 rlt = path_is_mount_point(dirlink1, AT_SYMLINK_FOLLOW);
432 /* its parent is a mount point, but not /file itself */
433 rl1f = path_is_mount_point(dirlink1file, 0);
434 rl1t = path_is_mount_point(dirlink1file, AT_SYMLINK_FOLLOW);
435
436 assert_se(umount(dir1) == 0);
437
438 assert_se(rf == 1);
439 assert_se(rt == 1);
440 assert_se(rlf == 0);
441 assert_se(rlt == 1);
442 assert_se(rl1f == 0);
443 assert_se(rl1t == 0);
444
5d409034
MP
445 } else
446 printf("Skipping bind mount file test: %m\n");
447
448 assert_se(rm_rf(tmp_dir, REMOVE_ROOT|REMOVE_PHYSICAL) == 0);
449}
450
7f076504 451int main(int argc, char **argv) {
76877b46 452 test_path();
b63bd109
ZJS
453 test_find_binary(argv[0], true);
454 test_find_binary(argv[0], false);
fecffe5d 455 test_prefixes();
0c6ea3a4 456 test_path_join();
eb66db55 457 test_fsck_exists();
6b56a651 458 test_make_relative();
3e8a78c8 459 test_strv_resolve();
5895b62f 460 test_path_startswith();
1d13f648 461 test_prefix_root();
5d409034 462 test_path_is_mount_point();
5895b62f 463
76877b46
ZJS
464 return 0;
465}