]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/test/test-path-util.c
path-util: make use of "mnt_id" field exported in /proc/self/fdinfo/<fd> to test...
[thirdparty/systemd.git] / src / test / test-path-util.c
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
22 #include <stdio.h>
23 #include <unistd.h>
24
25 #include "path-util.h"
26 #include "util.h"
27 #include "macro.h"
28 #include "strv.h"
29 #include "rm-rf.h"
30
31 #define test_path_compare(a, b, result) { \
32 assert_se(path_compare(a, b) == result); \
33 assert_se(path_compare(b, a) == -result); \
34 assert_se(path_equal(a, b) == !result); \
35 assert_se(path_equal(b, a) == !result); \
36 }
37
38 static void test_path(void) {
39 _cleanup_close_ int fd = -1;
40
41 test_path_compare("/goo", "/goo", 0);
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
47 test_path_compare("/goo/boo", "/goo//boo", 0);
48 test_path_compare("//goo/boo", "/goo/boo//", 0);
49
50 test_path_compare("/", "///", 0);
51
52 test_path_compare("/x", "x/", 1);
53 test_path_compare("x/", "/", -1);
54
55 test_path_compare("/x/./y", "x/y", 1);
56 test_path_compare("x/.y", "x/y", -1);
57
58 test_path_compare("foo", "/foo", -1);
59 test_path_compare("/foo", "/foo/bar", -1);
60 test_path_compare("/foo/aaa", "/foo/b", -1);
61 test_path_compare("/foo/aaa", "/foo/b/a", -1);
62 test_path_compare("/foo/a", "/foo/aaa", -1);
63 test_path_compare("/foo/a/b", "/foo/aaa", -1);
64
65 assert_se(path_is_absolute("/"));
66 assert_se(!path_is_absolute("./"));
67
68 assert_se(is_path("/dir"));
69 assert_se(is_path("a/b"));
70 assert_se(!is_path("."));
71
72 assert_se(streq(basename("./aa/bb/../file.da."), "file.da."));
73 assert_se(streq(basename("/aa///.file"), ".file"));
74 assert_se(streq(basename("/aa///file..."), "file..."));
75 assert_se(streq(basename("file.../"), ""));
76
77 #define test_parent(x, y) { \
78 _cleanup_free_ char *z = NULL; \
79 int r = path_get_parent(x, &z); \
80 printf("expected: %s\n", y ? y : "error"); \
81 printf("actual: %s\n", r<0 ? "error" : z); \
82 assert_se((y==NULL) ^ (r==0)); \
83 assert_se(y==NULL || path_equal(z, y)); \
84 }
85
86 test_parent("./aa/bb/../file.da.", "./aa/bb/..");
87 test_parent("/aa///.file", "/aa///");
88 test_parent("/aa///file...", "/aa///");
89 test_parent("file.../", NULL);
90
91 assert_se(path_is_mount_point("/", true) > 0);
92 assert_se(path_is_mount_point("/", false) > 0);
93
94 fd = open("/", O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOCTTY);
95 assert_se(fd >= 0);
96 assert_se(fd_is_mount_point(fd) > 0);
97
98 assert_se(path_is_mount_point("/proc", true) > 0);
99 assert_se(path_is_mount_point("/proc", false) > 0);
100
101 assert_se(path_is_mount_point("/proc/1", true) == 0);
102 assert_se(path_is_mount_point("/proc/1", false) == 0);
103
104 assert_se(path_is_mount_point("/sys", true) > 0);
105 assert_se(path_is_mount_point("/sys", false) > 0);
106
107 {
108 char p1[] = "aaa/bbb////ccc";
109 char p2[] = "//aaa/.////ccc";
110 char p3[] = "/./";
111
112 assert_se(path_equal(path_kill_slashes(p1), "aaa/bbb/ccc"));
113 assert_se(path_equal(path_kill_slashes(p2), "/aaa/./ccc"));
114 assert_se(path_equal(path_kill_slashes(p3), "/./"));
115 }
116 }
117
118 static void test_find_binary(const char *self, bool local) {
119 char *p;
120
121 assert_se(find_binary("/bin/sh", local, &p) == 0);
122 puts(p);
123 assert_se(streq(p, "/bin/sh"));
124 free(p);
125
126 assert_se(find_binary(self, local, &p) == 0);
127 puts(p);
128 assert_se(endswith(p, "/test-path-util"));
129 assert_se(path_is_absolute(p));
130 free(p);
131
132 assert_se(find_binary("sh", local, &p) == 0);
133 puts(p);
134 assert_se(endswith(p, "/sh"));
135 assert_se(path_is_absolute(p));
136 free(p);
137
138 assert_se(find_binary("xxxx-xxxx", local, &p) == -ENOENT);
139
140 assert_se(find_binary("/some/dir/xxxx-xxxx", local, &p) ==
141 (local ? -ENOENT : 0));
142 if (!local)
143 free(p);
144 }
145
146 static void test_prefixes(void) {
147 static const char* values[] = { "/a/b/c/d", "/a/b/c", "/a/b", "/a", "", NULL};
148 unsigned i;
149 char s[PATH_MAX];
150 bool b;
151
152 i = 0;
153 PATH_FOREACH_PREFIX_MORE(s, "/a/b/c/d") {
154 log_error("---%s---", s);
155 assert_se(streq(s, values[i++]));
156 }
157 assert_se(values[i] == NULL);
158
159 i = 1;
160 PATH_FOREACH_PREFIX(s, "/a/b/c/d") {
161 log_error("---%s---", s);
162 assert_se(streq(s, values[i++]));
163 }
164 assert_se(values[i] == NULL);
165
166 i = 0;
167 PATH_FOREACH_PREFIX_MORE(s, "////a////b////c///d///////")
168 assert_se(streq(s, values[i++]));
169 assert_se(values[i] == NULL);
170
171 i = 1;
172 PATH_FOREACH_PREFIX(s, "////a////b////c///d///////")
173 assert_se(streq(s, values[i++]));
174 assert_se(values[i] == NULL);
175
176 PATH_FOREACH_PREFIX(s, "////")
177 assert_not_reached("Wut?");
178
179 b = false;
180 PATH_FOREACH_PREFIX_MORE(s, "////") {
181 assert_se(!b);
182 assert_se(streq(s, ""));
183 b = true;
184 }
185 assert_se(b);
186
187 PATH_FOREACH_PREFIX(s, "")
188 assert_not_reached("wut?");
189
190 b = false;
191 PATH_FOREACH_PREFIX_MORE(s, "") {
192 assert_se(!b);
193 assert_se(streq(s, ""));
194 b = true;
195 }
196 }
197
198 static void test_path_join(void) {
199
200 #define test_join(root, path, rest, expected) { \
201 _cleanup_free_ char *z = NULL; \
202 z = path_join(root, path, rest); \
203 assert_se(streq(z, expected)); \
204 }
205
206 test_join("/root", "/a/b", "/c", "/root/a/b/c");
207 test_join("/root", "a/b", "c", "/root/a/b/c");
208 test_join("/root", "/a/b", "c", "/root/a/b/c");
209 test_join("/root", "/", "c", "/root/c");
210 test_join("/root", "/", NULL, "/root/");
211
212 test_join(NULL, "/a/b", "/c", "/a/b/c");
213 test_join(NULL, "a/b", "c", "a/b/c");
214 test_join(NULL, "/a/b", "c", "/a/b/c");
215 test_join(NULL, "/", "c", "/c");
216 test_join(NULL, "/", NULL, "/");
217 }
218
219 static void test_fsck_exists(void) {
220 /* Ensure we use a sane default for PATH. */
221 unsetenv("PATH");
222
223 /* fsck.minix is provided by util-linux and will probably exist. */
224 assert_se(fsck_exists("minix") == 0);
225
226 assert_se(fsck_exists("AbCdE") == -ENOENT);
227 }
228
229 static void test_make_relative(void) {
230 char *result;
231
232 assert_se(path_make_relative("some/relative/path", "/some/path", &result) < 0);
233 assert_se(path_make_relative("/some/path", "some/relative/path", &result) < 0);
234
235 #define test(from_dir, to_path, expected) { \
236 _cleanup_free_ char *z = NULL; \
237 path_make_relative(from_dir, to_path, &z); \
238 assert_se(streq(z, expected)); \
239 }
240
241 test("/", "/", ".");
242 test("/", "/some/path", "some/path");
243 test("/some/path", "/some/path", ".");
244 test("/some/path", "/some/path/in/subdir", "in/subdir");
245 test("/some/path", "/", "../..");
246 test("/some/path", "/some/other/path", "../other/path");
247 test("//extra/////slashes///won't////fool///anybody//", "////extra///slashes////are/just///fine///", "../../../are/just/fine");
248 }
249
250 static void test_strv_resolve(void) {
251 char tmp_dir[] = "/tmp/test-path-util-XXXXXX";
252 _cleanup_strv_free_ char **search_dirs = NULL;
253 _cleanup_strv_free_ char **absolute_dirs = NULL;
254 char **d;
255
256 assert_se(mkdtemp(tmp_dir) != NULL);
257
258 search_dirs = strv_new("/dir1", "/dir2", "/dir3", NULL);
259 assert_se(search_dirs);
260 STRV_FOREACH(d, search_dirs) {
261 char *p = strappend(tmp_dir, *d);
262 assert_se(p);
263 assert_se(strv_push(&absolute_dirs, p) == 0);
264 }
265
266 assert_se(mkdir(absolute_dirs[0], 0700) == 0);
267 assert_se(mkdir(absolute_dirs[1], 0700) == 0);
268 assert_se(symlink("dir2", absolute_dirs[2]) == 0);
269
270 path_strv_resolve(search_dirs, tmp_dir);
271 assert_se(streq(search_dirs[0], "/dir1"));
272 assert_se(streq(search_dirs[1], "/dir2"));
273 assert_se(streq(search_dirs[2], "/dir2"));
274
275 assert_se(rm_rf(tmp_dir, REMOVE_ROOT|REMOVE_PHYSICAL) == 0);
276 }
277
278 static void test_path_startswith(void) {
279 assert_se(path_startswith("/foo/bar/barfoo/", "/foo"));
280 assert_se(path_startswith("/foo/bar/barfoo/", "/foo/"));
281 assert_se(path_startswith("/foo/bar/barfoo/", "/"));
282 assert_se(path_startswith("/foo/bar/barfoo/", "////"));
283 assert_se(path_startswith("/foo/bar/barfoo/", "/foo//bar/////barfoo///"));
284 assert_se(path_startswith("/foo/bar/barfoo/", "/foo/bar/barfoo////"));
285 assert_se(path_startswith("/foo/bar/barfoo/", "/foo/bar///barfoo/"));
286 assert_se(path_startswith("/foo/bar/barfoo/", "/foo////bar/barfoo/"));
287 assert_se(path_startswith("/foo/bar/barfoo/", "////foo/bar/barfoo/"));
288 assert_se(path_startswith("/foo/bar/barfoo/", "/foo/bar/barfoo"));
289
290 assert_se(!path_startswith("/foo/bar/barfoo/", "/foo/bar/barfooa/"));
291 assert_se(!path_startswith("/foo/bar/barfoo/", "/foo/bar/barfooa"));
292 assert_se(!path_startswith("/foo/bar/barfoo/", ""));
293 assert_se(!path_startswith("/foo/bar/barfoo/", "/bar/foo"));
294 assert_se(!path_startswith("/foo/bar/barfoo/", "/f/b/b/"));
295 }
296
297 int main(int argc, char **argv) {
298 test_path();
299 test_find_binary(argv[0], true);
300 test_find_binary(argv[0], false);
301 test_prefixes();
302 test_path_join();
303 test_fsck_exists();
304 test_make_relative();
305 test_strv_resolve();
306 test_path_startswith();
307
308 return 0;
309 }