]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/test/test-path-util.c
util-lib: handle empty string in last_path_component
[thirdparty/systemd.git] / src / test / test-path-util.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
76877b46
ZJS
2/***
3 This file is part of systemd.
4
5 Copyright 2013 Zbigniew Jędrzejewski-Szmek
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19***/
20
a696dbef 21#include <stdio.h>
07630cea 22#include <unistd.h>
a696dbef 23
b5efdb8a 24#include "alloc-util.h"
3ffd4af2 25#include "fd-util.h"
76877b46 26#include "macro.h"
4349cd7c 27#include "mount-util.h"
07630cea 28#include "path-util.h"
c6878637 29#include "rm-rf.h"
84e72b5e 30#include "stat-util.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 93 }
3ae5990c
ZJS
94
95 assert_se(PATH_IN_SET("/bin", "/", "/bin", "/foo"));
96 assert_se(PATH_IN_SET("/bin", "/bin"));
97 assert_se(PATH_IN_SET("/bin", "/foo/bar", "/bin"));
98 assert_se(PATH_IN_SET("/", "/", "/", "/foo/bar"));
99 assert_se(!PATH_IN_SET("/", "/abc", "/def"));
24737c29
ZJS
100
101 assert_se(path_equal_ptr(NULL, NULL));
102 assert_se(path_equal_ptr("/a", "/a"));
103 assert_se(!path_equal_ptr("/a", "/b"));
104 assert_se(!path_equal_ptr("/a", NULL));
105 assert_se(!path_equal_ptr(NULL, "/a"));
76877b46
ZJS
106}
107
84e72b5e
ZJS
108static void test_path_equal_root(void) {
109 /* Nail down the details of how path_equal("/", ...) works. */
110
111 assert_se(path_equal("/", "/"));
112 assert_se(path_equal("/", "//"));
113
114 assert_se(!path_equal("/", "/./"));
115 assert_se(!path_equal("/", "/../"));
116
117 assert_se(!path_equal("/", "/.../"));
118
119 /* Make sure that files_same works as expected. */
120
e3f791a2
ZJS
121 assert_se(files_same("/", "/", 0) > 0);
122 assert_se(files_same("/", "/", AT_SYMLINK_NOFOLLOW) > 0);
123 assert_se(files_same("/", "//", 0) > 0);
124 assert_se(files_same("/", "//", AT_SYMLINK_NOFOLLOW) > 0);
84e72b5e 125
e3f791a2
ZJS
126 assert_se(files_same("/", "/./", 0) > 0);
127 assert_se(files_same("/", "/./", AT_SYMLINK_NOFOLLOW) > 0);
128 assert_se(files_same("/", "/../", 0) > 0);
129 assert_se(files_same("/", "/../", AT_SYMLINK_NOFOLLOW) > 0);
84e72b5e 130
e3f791a2
ZJS
131 assert_se(files_same("/", "/.../", 0) == -ENOENT);
132 assert_se(files_same("/", "/.../", AT_SYMLINK_NOFOLLOW) == -ENOENT);
84e72b5e
ZJS
133
134 /* The same for path_equal_or_files_same. */
135
e3f791a2
ZJS
136 assert_se(path_equal_or_files_same("/", "/", 0));
137 assert_se(path_equal_or_files_same("/", "/", AT_SYMLINK_NOFOLLOW));
138 assert_se(path_equal_or_files_same("/", "//", 0));
139 assert_se(path_equal_or_files_same("/", "//", AT_SYMLINK_NOFOLLOW));
84e72b5e 140
e3f791a2
ZJS
141 assert_se(path_equal_or_files_same("/", "/./", 0));
142 assert_se(path_equal_or_files_same("/", "/./", AT_SYMLINK_NOFOLLOW));
143 assert_se(path_equal_or_files_same("/", "/../", 0));
144 assert_se(path_equal_or_files_same("/", "/../", AT_SYMLINK_NOFOLLOW));
84e72b5e 145
e3f791a2
ZJS
146 assert_se(!path_equal_or_files_same("/", "/.../", 0));
147 assert_se(!path_equal_or_files_same("/", "/.../", AT_SYMLINK_NOFOLLOW));
84e72b5e
ZJS
148}
149
85eca92e 150static void test_find_binary(const char *self) {
c9d954b2
ZJS
151 char *p;
152
85eca92e 153 assert_se(find_binary("/bin/sh", &p) == 0);
c9d954b2 154 puts(p);
85eca92e 155 assert_se(path_equal(p, "/bin/sh"));
c9d954b2
ZJS
156 free(p);
157
85eca92e 158 assert_se(find_binary(self, &p) == 0);
c9d954b2 159 puts(p);
6d1e2ddd
MG
160 /* libtool might prefix the binary name with "lt-" */
161 assert_se(endswith(p, "/lt-test-path-util") || endswith(p, "/test-path-util"));
8d95631e 162 assert_se(path_is_absolute(p));
c9d954b2
ZJS
163 free(p);
164
85eca92e 165 assert_se(find_binary("sh", &p) == 0);
c9d954b2 166 puts(p);
8d95631e
FB
167 assert_se(endswith(p, "/sh"));
168 assert_se(path_is_absolute(p));
c9d954b2
ZJS
169 free(p);
170
85eca92e
LP
171 assert_se(find_binary("xxxx-xxxx", &p) == -ENOENT);
172 assert_se(find_binary("/some/dir/xxxx-xxxx", &p) == -ENOENT);
c9d954b2
ZJS
173}
174
fecffe5d 175static void test_prefixes(void) {
e203f7c3
LP
176 static const char* values[] = { "/a/b/c/d", "/a/b/c", "/a/b", "/a", "", NULL};
177 unsigned i;
fecffe5d 178 char s[PATH_MAX];
e203f7c3 179 bool b;
fecffe5d 180
e203f7c3
LP
181 i = 0;
182 PATH_FOREACH_PREFIX_MORE(s, "/a/b/c/d") {
fecffe5d
LP
183 log_error("---%s---", s);
184 assert_se(streq(s, values[i++]));
185 }
e203f7c3 186 assert_se(values[i] == NULL);
fecffe5d 187
e203f7c3
LP
188 i = 1;
189 PATH_FOREACH_PREFIX(s, "/a/b/c/d") {
190 log_error("---%s---", s);
191 assert_se(streq(s, values[i++]));
192 }
fecffe5d
LP
193 assert_se(values[i] == NULL);
194
195 i = 0;
e203f7c3 196 PATH_FOREACH_PREFIX_MORE(s, "////a////b////c///d///////")
fecffe5d 197 assert_se(streq(s, values[i++]));
e203f7c3 198 assert_se(values[i] == NULL);
fecffe5d 199
e203f7c3
LP
200 i = 1;
201 PATH_FOREACH_PREFIX(s, "////a////b////c///d///////")
202 assert_se(streq(s, values[i++]));
fecffe5d
LP
203 assert_se(values[i] == NULL);
204
205 PATH_FOREACH_PREFIX(s, "////")
e203f7c3
LP
206 assert_not_reached("Wut?");
207
208 b = false;
209 PATH_FOREACH_PREFIX_MORE(s, "////") {
210 assert_se(!b);
fecffe5d 211 assert_se(streq(s, ""));
e203f7c3
LP
212 b = true;
213 }
214 assert_se(b);
fecffe5d
LP
215
216 PATH_FOREACH_PREFIX(s, "")
217 assert_not_reached("wut?");
218
e203f7c3
LP
219 b = false;
220 PATH_FOREACH_PREFIX_MORE(s, "") {
8d95631e
FB
221 assert_se(!b);
222 assert_se(streq(s, ""));
e203f7c3
LP
223 b = true;
224 }
fecffe5d
LP
225}
226
0c6ea3a4 227static void test_path_join(void) {
59ae3a95
TA
228
229#define test_join(root, path, rest, expected) { \
230 _cleanup_free_ char *z = NULL; \
231 z = path_join(root, path, rest); \
232 assert_se(streq(z, expected)); \
233 }
234
235 test_join("/root", "/a/b", "/c", "/root/a/b/c");
236 test_join("/root", "a/b", "c", "/root/a/b/c");
237 test_join("/root", "/a/b", "c", "/root/a/b/c");
bc854dc7 238 test_join("/root", "/", "c", "/root/c");
59ae3a95
TA
239 test_join("/root", "/", NULL, "/root/");
240
241 test_join(NULL, "/a/b", "/c", "/a/b/c");
242 test_join(NULL, "a/b", "c", "a/b/c");
243 test_join(NULL, "/a/b", "c", "/a/b/c");
bc854dc7 244 test_join(NULL, "/", "c", "/c");
59ae3a95 245 test_join(NULL, "/", NULL, "/");
0c6ea3a4
ZJS
246}
247
eb66db55
MG
248static void test_fsck_exists(void) {
249 /* Ensure we use a sane default for PATH. */
250 unsetenv("PATH");
251
252 /* fsck.minix is provided by util-linux and will probably exist. */
85eca92e 253 assert_se(fsck_exists("minix") == 1);
eb66db55 254
85eca92e
LP
255 assert_se(fsck_exists("AbCdE") == 0);
256 assert_se(fsck_exists("/../bin/") == 0);
eb66db55
MG
257}
258
6b56a651
TK
259static void test_make_relative(void) {
260 char *result;
261
262 assert_se(path_make_relative("some/relative/path", "/some/path", &result) < 0);
263 assert_se(path_make_relative("/some/path", "some/relative/path", &result) < 0);
2a5beb66 264 assert_se(path_make_relative("/some/dotdot/../path", "/some/path", &result) < 0);
6b56a651 265
59ae3a95
TA
266#define test(from_dir, to_path, expected) { \
267 _cleanup_free_ char *z = NULL; \
268 path_make_relative(from_dir, to_path, &z); \
269 assert_se(streq(z, expected)); \
6b56a651
TK
270 }
271
272 test("/", "/", ".");
273 test("/", "/some/path", "some/path");
274 test("/some/path", "/some/path", ".");
275 test("/some/path", "/some/path/in/subdir", "in/subdir");
276 test("/some/path", "/", "../..");
277 test("/some/path", "/some/other/path", "../other/path");
2a5beb66 278 test("/some/path/./dot", "/some/further/path", "../../further/path");
6b56a651
TK
279 test("//extra/////slashes///won't////fool///anybody//", "////extra///slashes////are/just///fine///", "../../../are/just/fine");
280}
281
3e8a78c8
MM
282static void test_strv_resolve(void) {
283 char tmp_dir[] = "/tmp/test-path-util-XXXXXX";
284 _cleanup_strv_free_ char **search_dirs = NULL;
285 _cleanup_strv_free_ char **absolute_dirs = NULL;
286 char **d;
287
288 assert_se(mkdtemp(tmp_dir) != NULL);
289
290 search_dirs = strv_new("/dir1", "/dir2", "/dir3", NULL);
291 assert_se(search_dirs);
292 STRV_FOREACH(d, search_dirs) {
293 char *p = strappend(tmp_dir, *d);
294 assert_se(p);
295 assert_se(strv_push(&absolute_dirs, p) == 0);
296 }
297
298 assert_se(mkdir(absolute_dirs[0], 0700) == 0);
299 assert_se(mkdir(absolute_dirs[1], 0700) == 0);
300 assert_se(symlink("dir2", absolute_dirs[2]) == 0);
301
302 path_strv_resolve(search_dirs, tmp_dir);
303 assert_se(streq(search_dirs[0], "/dir1"));
304 assert_se(streq(search_dirs[1], "/dir2"));
305 assert_se(streq(search_dirs[2], "/dir2"));
306
c6878637 307 assert_se(rm_rf(tmp_dir, REMOVE_ROOT|REMOVE_PHYSICAL) == 0);
3e8a78c8
MM
308}
309
5895b62f 310static void test_path_startswith(void) {
0470289b
ZJS
311 const char *p;
312
313 p = path_startswith("/foo/bar/barfoo/", "/foo");
314 assert_se(streq_ptr(p, "bar/barfoo/"));
315
316 p = path_startswith("/foo/bar/barfoo/", "/foo/");
317 assert_se(streq_ptr(p, "bar/barfoo/"));
318
319 p = path_startswith("/foo/bar/barfoo/", "/");
320 assert_se(streq_ptr(p, "foo/bar/barfoo/"));
321
322 p = path_startswith("/foo/bar/barfoo/", "////");
323 assert_se(streq_ptr(p, "foo/bar/barfoo/"));
324
325 p = path_startswith("/foo/bar/barfoo/", "/foo//bar/////barfoo///");
326 assert_se(streq_ptr(p, ""));
327
328 p = path_startswith("/foo/bar/barfoo/", "/foo/bar/barfoo////");
329 assert_se(streq_ptr(p, ""));
330
331 p = path_startswith("/foo/bar/barfoo/", "/foo/bar///barfoo/");
332 assert_se(streq_ptr(p, ""));
333
334 p = path_startswith("/foo/bar/barfoo/", "/foo////bar/barfoo/");
335 assert_se(streq_ptr(p, ""));
336
337 p = path_startswith("/foo/bar/barfoo/", "////foo/bar/barfoo/");
338 assert_se(streq_ptr(p, ""));
339
340 p = path_startswith("/foo/bar/barfoo/", "/foo/bar/barfoo");
341 assert_se(streq_ptr(p, ""));
5895b62f
RC
342
343 assert_se(!path_startswith("/foo/bar/barfoo/", "/foo/bar/barfooa/"));
344 assert_se(!path_startswith("/foo/bar/barfoo/", "/foo/bar/barfooa"));
345 assert_se(!path_startswith("/foo/bar/barfoo/", ""));
346 assert_se(!path_startswith("/foo/bar/barfoo/", "/bar/foo"));
347 assert_se(!path_startswith("/foo/bar/barfoo/", "/f/b/b/"));
348}
349
1d13f648
LP
350static void test_prefix_root_one(const char *r, const char *p, const char *expected) {
351 _cleanup_free_ char *s = NULL;
352 const char *t;
353
354 assert_se(s = prefix_root(r, p));
355 assert_se(streq_ptr(s, expected));
356
357 t = prefix_roota(r, p);
358 assert_se(t);
359 assert_se(streq_ptr(t, expected));
360}
361
362static void test_prefix_root(void) {
363 test_prefix_root_one("/", "/foo", "/foo");
364 test_prefix_root_one(NULL, "/foo", "/foo");
365 test_prefix_root_one("", "/foo", "/foo");
366 test_prefix_root_one("///", "/foo", "/foo");
367 test_prefix_root_one("/", "////foo", "/foo");
368 test_prefix_root_one(NULL, "////foo", "/foo");
369
370 test_prefix_root_one("/foo", "/bar", "/foo/bar");
371 test_prefix_root_one("/foo", "bar", "/foo/bar");
372 test_prefix_root_one("foo", "bar", "foo/bar");
373 test_prefix_root_one("/foo/", "/bar", "/foo/bar");
374 test_prefix_root_one("/foo/", "//bar", "/foo/bar");
375 test_prefix_root_one("/foo///", "//bar", "/foo/bar");
376}
377
63292663
RC
378static void test_file_in_same_dir(void) {
379 char *t;
380
381 t = file_in_same_dir("/", "a");
382 assert_se(streq(t, "/a"));
383 free(t);
384
385 t = file_in_same_dir("/", "/a");
386 assert_se(streq(t, "/a"));
387 free(t);
388
389 t = file_in_same_dir("", "a");
390 assert_se(streq(t, "a"));
391 free(t);
392
393 t = file_in_same_dir("a/", "a");
394 assert_se(streq(t, "a/a"));
395 free(t);
396
397 t = file_in_same_dir("bar/foo", "bar");
398 assert_se(streq(t, "bar/bar"));
399 free(t);
400}
401
b12d25a8
ZJS
402static void test_last_path_component(void) {
403 assert_se(streq(last_path_component("a/b/c"), "c"));
404 assert_se(streq(last_path_component("a/b/c/"), "c/"));
405 assert_se(streq(last_path_component("/"), "/"));
406 assert_se(streq(last_path_component("//"), "/"));
407 assert_se(streq(last_path_component("///"), "/"));
408 assert_se(streq(last_path_component("."), "."));
409 assert_se(streq(last_path_component("./."), "."));
410 assert_se(streq(last_path_component("././"), "./"));
411 assert_se(streq(last_path_component("././/"), ".//"));
412 assert_se(streq(last_path_component("/foo/a"), "a"));
413 assert_se(streq(last_path_component("/foo/a/"), "a/"));
69f9ccf1 414 assert_se(streq(last_path_component(""), ""));
b12d25a8
ZJS
415}
416
63292663
RC
417static void test_filename_is_valid(void) {
418 char foo[FILENAME_MAX+2];
419 int i;
420
421 assert_se(!filename_is_valid(""));
422 assert_se(!filename_is_valid("/bar/foo"));
423 assert_se(!filename_is_valid("/"));
424 assert_se(!filename_is_valid("."));
425 assert_se(!filename_is_valid(".."));
426
427 for (i=0; i<FILENAME_MAX+1; i++)
428 foo[i] = 'a';
429 foo[FILENAME_MAX+1] = '\0';
430
431 assert_se(!filename_is_valid(foo));
432
433 assert_se(filename_is_valid("foo_bar-333"));
434 assert_se(filename_is_valid("o.o"));
435}
436
b05b9cde
ZJS
437static void test_hidden_or_backup_file(void) {
438 assert_se(hidden_or_backup_file(".hidden"));
439 assert_se(hidden_or_backup_file("..hidden"));
440 assert_se(!hidden_or_backup_file("hidden."));
441
442 assert_se(hidden_or_backup_file("backup~"));
443 assert_se(hidden_or_backup_file(".backup~"));
444
445 assert_se(hidden_or_backup_file("lost+found"));
446 assert_se(hidden_or_backup_file("aquota.user"));
447 assert_se(hidden_or_backup_file("aquota.group"));
448
449 assert_se(hidden_or_backup_file("test.rpmnew"));
450 assert_se(hidden_or_backup_file("test.dpkg-old"));
451 assert_se(hidden_or_backup_file("test.dpkg-remove"));
452 assert_se(hidden_or_backup_file("test.swp"));
453
454 assert_se(!hidden_or_backup_file("test.rpmnew."));
455 assert_se(!hidden_or_backup_file("test.dpkg-old.foo"));
456}
457
5a46d55f
ZJS
458static void test_systemd_installation_has_version(const char *path) {
459 int r;
460 const unsigned versions[] = {0, 231, atoi(PACKAGE_VERSION), 999};
461 unsigned i;
462
463 for (i = 0; i < ELEMENTSOF(versions); i++) {
464 r = systemd_installation_has_version(path, versions[i]);
465 assert_se(r >= 0);
466 log_info("%s has systemd >= %u: %s",
467 path ?: "Current installation", versions[i], yes_no(r));
468 }
469}
470
a119ec7c
LP
471static void test_skip_dev_prefix(void) {
472
473 assert_se(streq(skip_dev_prefix("/"), "/"));
474 assert_se(streq(skip_dev_prefix("/dev"), ""));
475 assert_se(streq(skip_dev_prefix("/dev/"), ""));
476 assert_se(streq(skip_dev_prefix("/dev/foo"), "foo"));
477 assert_se(streq(skip_dev_prefix("/dev/foo/bar"), "foo/bar"));
478 assert_se(streq(skip_dev_prefix("//dev"), ""));
479 assert_se(streq(skip_dev_prefix("//dev//"), ""));
480 assert_se(streq(skip_dev_prefix("/dev///foo"), "foo"));
481 assert_se(streq(skip_dev_prefix("///dev///foo///bar"), "foo///bar"));
482 assert_se(streq(skip_dev_prefix("//foo"), "//foo"));
483 assert_se(streq(skip_dev_prefix("foo"), "foo"));
484}
485
7f076504 486int main(int argc, char **argv) {
5a46d55f
ZJS
487 log_set_max_level(LOG_DEBUG);
488 log_parse_environment();
489 log_open();
490
76877b46 491 test_path();
84e72b5e 492 test_path_equal_root();
85eca92e 493 test_find_binary(argv[0]);
fecffe5d 494 test_prefixes();
0c6ea3a4 495 test_path_join();
eb66db55 496 test_fsck_exists();
6b56a651 497 test_make_relative();
3e8a78c8 498 test_strv_resolve();
5895b62f 499 test_path_startswith();
1d13f648 500 test_prefix_root();
63292663 501 test_file_in_same_dir();
b12d25a8 502 test_last_path_component();
63292663 503 test_filename_is_valid();
b05b9cde 504 test_hidden_or_backup_file();
a119ec7c 505 test_skip_dev_prefix();
5895b62f 506
5a46d55f
ZJS
507 test_systemd_installation_has_version(argv[1]); /* NULL is OK */
508
76877b46
ZJS
509 return 0;
510}