chiark / gitweb /
Prep v236 : Add missing SPDX-License-Identifier (8/9) src/test
[elogind.git] / src / test / test-path-util.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
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
21 #include <stdio.h>
22 #include <unistd.h>
23
24 #include "alloc-util.h"
25 #include "fd-util.h"
26 #include "macro.h"
27 #include "mount-util.h"
28 #include "path-util.h"
29 #include "rm-rf.h"
30 #include "stat-util.h"
31 #include "string-util.h"
32 #include "strv.h"
33 #include "util.h"
34
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         }
41
42 static void test_path(void) {
43         _cleanup_close_ int fd = -1;
44
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);
50
51         test_path_compare("/goo/boo", "/goo//boo", 0);
52         test_path_compare("//goo/boo", "/goo/boo//", 0);
53
54         test_path_compare("/", "///", 0);
55
56         test_path_compare("/x", "x/", 1);
57         test_path_compare("x/", "/", -1);
58
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);
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
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.../"), ""));
80
81         fd = open("/", O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOCTTY);
82         assert_se(fd >= 0);
83         assert_se(fd_is_mount_point(fd, "/", 0) > 0);
84
85         {
86                 char p1[] = "aaa/bbb////ccc";
87                 char p2[] = "//aaa/.////ccc";
88                 char p3[] = "/./";
89
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), "/./"));
93         }
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"));
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"));
106 }
107
108 static 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
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);
125
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);
130
131         assert_se(files_same("/", "/.../", 0) == -ENOENT);
132         assert_se(files_same("/", "/.../", AT_SYMLINK_NOFOLLOW) == -ENOENT);
133
134         /* The same for path_equal_or_files_same. */
135
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));
140
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));
145
146         assert_se(!path_equal_or_files_same("/", "/.../", 0));
147         assert_se(!path_equal_or_files_same("/", "/.../", AT_SYMLINK_NOFOLLOW));
148 }
149
150 static void test_find_binary(const char *self) {
151         char *p;
152
153         assert_se(find_binary("/bin/sh", &p) == 0);
154         puts(p);
155         assert_se(path_equal(p, "/bin/sh"));
156         free(p);
157
158         assert_se(find_binary(self, &p) == 0);
159         puts(p);
160         /* libtool might prefix the binary name with "lt-" */
161         assert_se(endswith(p, "/lt-test-path-util") || endswith(p, "/test-path-util"));
162         assert_se(path_is_absolute(p));
163         free(p);
164
165         assert_se(find_binary("sh", &p) == 0);
166         puts(p);
167         assert_se(endswith(p, "/sh"));
168         assert_se(path_is_absolute(p));
169         free(p);
170
171         assert_se(find_binary("xxxx-xxxx", &p) == -ENOENT);
172         assert_se(find_binary("/some/dir/xxxx-xxxx", &p) == -ENOENT);
173 }
174
175 static void test_prefixes(void) {
176         static const char* values[] = { "/a/b/c/d", "/a/b/c", "/a/b", "/a", "", NULL};
177         unsigned i;
178         char s[PATH_MAX];
179         bool b;
180
181         i = 0;
182         PATH_FOREACH_PREFIX_MORE(s, "/a/b/c/d") {
183                 log_error("---%s---", s);
184                 assert_se(streq(s, values[i++]));
185         }
186         assert_se(values[i] == NULL);
187
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         }
193         assert_se(values[i] == NULL);
194
195         i = 0;
196         PATH_FOREACH_PREFIX_MORE(s, "////a////b////c///d///////")
197                 assert_se(streq(s, values[i++]));
198         assert_se(values[i] == NULL);
199
200         i = 1;
201         PATH_FOREACH_PREFIX(s, "////a////b////c///d///////")
202                 assert_se(streq(s, values[i++]));
203         assert_se(values[i] == NULL);
204
205         PATH_FOREACH_PREFIX(s, "////")
206                 assert_not_reached("Wut?");
207
208         b = false;
209         PATH_FOREACH_PREFIX_MORE(s, "////") {
210                 assert_se(!b);
211                 assert_se(streq(s, ""));
212                 b = true;
213         }
214         assert_se(b);
215
216         PATH_FOREACH_PREFIX(s, "")
217                 assert_not_reached("wut?");
218
219         b = false;
220         PATH_FOREACH_PREFIX_MORE(s, "") {
221                 assert_se(!b);
222                 assert_se(streq(s, ""));
223                 b = true;
224         }
225 }
226
227 static void test_path_join(void) {
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");
238         test_join("/root", "/", "c", "/root/c");
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");
244         test_join(NULL, "/", "c", "/c");
245         test_join(NULL, "/", NULL, "/");
246 }
247
248 #if 0 /// UNNEEDED by elogind
249 static void test_fsck_exists(void) {
250         /* Ensure we use a sane default for PATH. */
251         unsetenv("PATH");
252
253         /* fsck.minix is provided by util-linux and will probably exist. */
254         assert_se(fsck_exists("minix") == 1);
255
256         assert_se(fsck_exists("AbCdE") == 0);
257         assert_se(fsck_exists("/../bin/") == 0);
258 }
259
260 static void test_make_relative(void) {
261         char *result;
262
263         assert_se(path_make_relative("some/relative/path", "/some/path", &result) < 0);
264         assert_se(path_make_relative("/some/path", "some/relative/path", &result) < 0);
265         assert_se(path_make_relative("/some/dotdot/../path", "/some/path", &result) < 0);
266
267 #define test(from_dir, to_path, expected) {                \
268                 _cleanup_free_ char *z = NULL;             \
269                 path_make_relative(from_dir, to_path, &z); \
270                 assert_se(streq(z, expected));             \
271         }
272
273         test("/", "/", ".");
274         test("/", "/some/path", "some/path");
275         test("/some/path", "/some/path", ".");
276         test("/some/path", "/some/path/in/subdir", "in/subdir");
277         test("/some/path", "/", "../..");
278         test("/some/path", "/some/other/path", "../other/path");
279         test("/some/path/./dot", "/some/further/path", "../../further/path");
280         test("//extra/////slashes///won't////fool///anybody//", "////extra///slashes////are/just///fine///", "../../../are/just/fine");
281 }
282 #endif // 0
283
284 static void test_strv_resolve(void) {
285         char tmp_dir[] = "/tmp/test-path-util-XXXXXX";
286         _cleanup_strv_free_ char **search_dirs = NULL;
287         _cleanup_strv_free_ char **absolute_dirs = NULL;
288         char **d;
289
290         assert_se(mkdtemp(tmp_dir) != NULL);
291
292         search_dirs = strv_new("/dir1", "/dir2", "/dir3", NULL);
293         assert_se(search_dirs);
294         STRV_FOREACH(d, search_dirs) {
295                 char *p = strappend(tmp_dir, *d);
296                 assert_se(p);
297                 assert_se(strv_push(&absolute_dirs, p) == 0);
298         }
299
300         assert_se(mkdir(absolute_dirs[0], 0700) == 0);
301         assert_se(mkdir(absolute_dirs[1], 0700) == 0);
302         assert_se(symlink("dir2", absolute_dirs[2]) == 0);
303
304         path_strv_resolve(search_dirs, tmp_dir);
305         assert_se(streq(search_dirs[0], "/dir1"));
306         assert_se(streq(search_dirs[1], "/dir2"));
307         assert_se(streq(search_dirs[2], "/dir2"));
308
309         assert_se(rm_rf(tmp_dir, REMOVE_ROOT|REMOVE_PHYSICAL) == 0);
310 }
311
312 static void test_path_startswith(void) {
313         const char *p;
314
315         p = path_startswith("/foo/bar/barfoo/", "/foo");
316         assert_se(streq_ptr(p, "bar/barfoo/"));
317
318         p = path_startswith("/foo/bar/barfoo/", "/foo/");
319         assert_se(streq_ptr(p, "bar/barfoo/"));
320
321         p = path_startswith("/foo/bar/barfoo/", "/");
322         assert_se(streq_ptr(p, "foo/bar/barfoo/"));
323
324         p = path_startswith("/foo/bar/barfoo/", "////");
325         assert_se(streq_ptr(p, "foo/bar/barfoo/"));
326
327         p = path_startswith("/foo/bar/barfoo/", "/foo//bar/////barfoo///");
328         assert_se(streq_ptr(p, ""));
329
330         p = path_startswith("/foo/bar/barfoo/", "/foo/bar/barfoo////");
331         assert_se(streq_ptr(p, ""));
332
333         p = path_startswith("/foo/bar/barfoo/", "/foo/bar///barfoo/");
334         assert_se(streq_ptr(p, ""));
335
336         p = path_startswith("/foo/bar/barfoo/", "/foo////bar/barfoo/");
337         assert_se(streq_ptr(p, ""));
338
339         p = path_startswith("/foo/bar/barfoo/", "////foo/bar/barfoo/");
340         assert_se(streq_ptr(p, ""));
341
342         p = path_startswith("/foo/bar/barfoo/", "/foo/bar/barfoo");
343         assert_se(streq_ptr(p, ""));
344
345         assert_se(!path_startswith("/foo/bar/barfoo/", "/foo/bar/barfooa/"));
346         assert_se(!path_startswith("/foo/bar/barfoo/", "/foo/bar/barfooa"));
347         assert_se(!path_startswith("/foo/bar/barfoo/", ""));
348         assert_se(!path_startswith("/foo/bar/barfoo/", "/bar/foo"));
349         assert_se(!path_startswith("/foo/bar/barfoo/", "/f/b/b/"));
350 }
351
352 static void test_prefix_root_one(const char *r, const char *p, const char *expected) {
353         _cleanup_free_ char *s = NULL;
354         const char *t;
355
356         assert_se(s = prefix_root(r, p));
357         assert_se(streq_ptr(s, expected));
358
359         t = prefix_roota(r, p);
360         assert_se(t);
361         assert_se(streq_ptr(t, expected));
362 }
363
364 static void test_prefix_root(void) {
365         test_prefix_root_one("/", "/foo", "/foo");
366         test_prefix_root_one(NULL, "/foo", "/foo");
367         test_prefix_root_one("", "/foo", "/foo");
368         test_prefix_root_one("///", "/foo", "/foo");
369         test_prefix_root_one("/", "////foo", "/foo");
370         test_prefix_root_one(NULL, "////foo", "/foo");
371
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         test_prefix_root_one("/foo/", "//bar", "/foo/bar");
377         test_prefix_root_one("/foo///", "//bar", "/foo/bar");
378 }
379
380 static void test_file_in_same_dir(void) {
381         char *t;
382
383         t = file_in_same_dir("/", "a");
384         assert_se(streq(t, "/a"));
385         free(t);
386
387         t = file_in_same_dir("/", "/a");
388         assert_se(streq(t, "/a"));
389         free(t);
390
391         t = file_in_same_dir("", "a");
392         assert_se(streq(t, "a"));
393         free(t);
394
395         t = file_in_same_dir("a/", "a");
396         assert_se(streq(t, "a/a"));
397         free(t);
398
399         t = file_in_same_dir("bar/foo", "bar");
400         assert_se(streq(t, "bar/bar"));
401         free(t);
402 }
403
404 static void test_last_path_component(void) {
405         assert_se(streq(last_path_component("a/b/c"), "c"));
406         assert_se(streq(last_path_component("a/b/c/"), "c/"));
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("././"), "./"));
413         assert_se(streq(last_path_component("././/"), ".//"));
414         assert_se(streq(last_path_component("/foo/a"), "a"));
415         assert_se(streq(last_path_component("/foo/a/"), "a/"));
416         assert_se(streq(last_path_component(""), ""));
417 }
418
419 static void test_filename_is_valid(void) {
420         char foo[FILENAME_MAX+2];
421         int i;
422
423         assert_se(!filename_is_valid(""));
424         assert_se(!filename_is_valid("/bar/foo"));
425         assert_se(!filename_is_valid("/"));
426         assert_se(!filename_is_valid("."));
427         assert_se(!filename_is_valid(".."));
428
429         for (i=0; i<FILENAME_MAX+1; i++)
430                 foo[i] = 'a';
431         foo[FILENAME_MAX+1] = '\0';
432
433         assert_se(!filename_is_valid(foo));
434
435         assert_se(filename_is_valid("foo_bar-333"));
436         assert_se(filename_is_valid("o.o"));
437 }
438
439 static void test_hidden_or_backup_file(void) {
440         assert_se(hidden_or_backup_file(".hidden"));
441         assert_se(hidden_or_backup_file("..hidden"));
442         assert_se(!hidden_or_backup_file("hidden."));
443
444         assert_se(hidden_or_backup_file("backup~"));
445         assert_se(hidden_or_backup_file(".backup~"));
446
447         assert_se(hidden_or_backup_file("lost+found"));
448         assert_se(hidden_or_backup_file("aquota.user"));
449         assert_se(hidden_or_backup_file("aquota.group"));
450
451         assert_se(hidden_or_backup_file("test.rpmnew"));
452         assert_se(hidden_or_backup_file("test.dpkg-old"));
453         assert_se(hidden_or_backup_file("test.dpkg-remove"));
454         assert_se(hidden_or_backup_file("test.swp"));
455
456         assert_se(!hidden_or_backup_file("test.rpmnew."));
457         assert_se(!hidden_or_backup_file("test.dpkg-old.foo"));
458 }
459
460 #if 0 /// UNNEEDED by elogind
461 static void test_systemd_installation_has_version(const char *path) {
462         int r;
463         const unsigned versions[] = {0, 231, atoi(PACKAGE_VERSION), 999};
464         unsigned i;
465
466         for (i = 0; i < ELEMENTSOF(versions); i++) {
467                 r = systemd_installation_has_version(path, versions[i]);
468                 assert_se(r >= 0);
469                 log_info("%s has systemd >= %u: %s",
470                          path ?: "Current installation", versions[i], yes_no(r));
471         }
472 }
473 #endif // 0
474
475 static void test_skip_dev_prefix(void) {
476
477         assert_se(streq(skip_dev_prefix("/"), "/"));
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("//dev"), ""));
483         assert_se(streq(skip_dev_prefix("//dev//"), ""));
484         assert_se(streq(skip_dev_prefix("/dev///foo"), "foo"));
485         assert_se(streq(skip_dev_prefix("///dev///foo///bar"), "foo///bar"));
486         assert_se(streq(skip_dev_prefix("//foo"), "//foo"));
487         assert_se(streq(skip_dev_prefix("foo"), "foo"));
488 }
489
490 int main(int argc, char **argv) {
491         log_set_max_level(LOG_DEBUG);
492         log_parse_environment();
493         log_open();
494
495         test_path();
496         test_path_equal_root();
497         test_find_binary(argv[0]);
498         test_prefixes();
499         test_path_join();
500 #if 0 /// UNNEEDED by elogind
501         test_fsck_exists();
502         test_make_relative();
503 #endif // 0
504         test_strv_resolve();
505         test_path_startswith();
506         test_prefix_root();
507         test_file_in_same_dir();
508         test_last_path_component();
509         test_filename_is_valid();
510         test_hidden_or_backup_file();
511         test_skip_dev_prefix();
512
513 #if 0 /// UNNEEDED by elogind
514         test_systemd_installation_has_version(argv[1]); /* NULL is OK */
515 #endif // 0
516
517         return 0;
518 }