chiark / gitweb /
Prep v236 : Add missing SPDX-License-Identifier (8/9) src/test
[elogind.git] / src / test / test-fs-util.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3   This file is part of systemd.
4
5   Copyright 2010 Lennart Poettering
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 <unistd.h>
22
23 #include "alloc-util.h"
24 #include "fd-util.h"
25 #include "fileio.h"
26 #include "fs-util.h"
27 #include "macro.h"
28 #include "mkdir.h"
29 #include "path-util.h"
30 #include "rm-rf.h"
31 #include "string-util.h"
32 #include "strv.h"
33 #include "util.h"
34
35 static void test_chase_symlinks(void) {
36         _cleanup_free_ char *result = NULL;
37         char temp[] = "/tmp/test-chase.XXXXXX";
38         const char *top, *p, *pslash, *q, *qslash;
39         int r;
40
41         assert_se(mkdtemp(temp));
42
43         top = strjoina(temp, "/top");
44         assert_se(mkdir(top, 0700) >= 0);
45
46         p = strjoina(top, "/dot");
47         assert_se(symlink(".", p) >= 0);
48
49         p = strjoina(top, "/dotdot");
50         assert_se(symlink("..", p) >= 0);
51
52         p = strjoina(top, "/dotdota");
53         assert_se(symlink("../a", p) >= 0);
54
55         p = strjoina(temp, "/a");
56         assert_se(symlink("b", p) >= 0);
57
58         p = strjoina(temp, "/b");
59         assert_se(symlink("/usr", p) >= 0);
60
61         p = strjoina(temp, "/start");
62         assert_se(symlink("top/dot/dotdota", p) >= 0);
63
64         /* Paths that use symlinks underneath the "root" */
65
66         r = chase_symlinks(p, NULL, 0, &result);
67         assert_se(r > 0);
68         assert_se(path_equal(result, "/usr"));
69         result = mfree(result);
70
71         pslash = strjoina(p, "/");
72         r = chase_symlinks(pslash, NULL, 0, &result);
73         assert_se(r > 0);
74         assert_se(path_equal(result, "/usr/"));
75         result = mfree(result);
76
77         r = chase_symlinks(p, temp, 0, &result);
78         assert_se(r == -ENOENT);
79
80         r = chase_symlinks(pslash, temp, 0, &result);
81         assert_se(r == -ENOENT);
82
83         q = strjoina(temp, "/usr");
84
85         r = chase_symlinks(p, temp, CHASE_NONEXISTENT, &result);
86         assert_se(r == 0);
87         assert_se(path_equal(result, q));
88         result = mfree(result);
89
90         qslash = strjoina(q, "/");
91
92         r = chase_symlinks(pslash, temp, CHASE_NONEXISTENT, &result);
93         assert_se(r == 0);
94         assert_se(path_equal(result, qslash));
95         result = mfree(result);
96
97         assert_se(mkdir(q, 0700) >= 0);
98
99         r = chase_symlinks(p, temp, 0, &result);
100         assert_se(r > 0);
101         assert_se(path_equal(result, q));
102         result = mfree(result);
103
104         r = chase_symlinks(pslash, temp, 0, &result);
105         assert_se(r > 0);
106         assert_se(path_equal(result, qslash));
107         result = mfree(result);
108
109         p = strjoina(temp, "/slash");
110         assert_se(symlink("/", p) >= 0);
111
112         r = chase_symlinks(p, NULL, 0, &result);
113         assert_se(r > 0);
114         assert_se(path_equal(result, "/"));
115         result = mfree(result);
116
117         r = chase_symlinks(p, temp, 0, &result);
118         assert_se(r > 0);
119         assert_se(path_equal(result, temp));
120         result = mfree(result);
121
122         /* Paths that would "escape" outside of the "root" */
123
124         p = strjoina(temp, "/6dots");
125         assert_se(symlink("../../..", p) >= 0);
126
127         r = chase_symlinks(p, temp, 0, &result);
128         assert_se(r > 0 && path_equal(result, temp));
129         result = mfree(result);
130
131         p = strjoina(temp, "/6dotsusr");
132         assert_se(symlink("../../../usr", p) >= 0);
133
134         r = chase_symlinks(p, temp, 0, &result);
135         assert_se(r > 0 && path_equal(result, q));
136         result = mfree(result);
137
138         p = strjoina(temp, "/top/8dotsusr");
139         assert_se(symlink("../../../../usr", p) >= 0);
140
141         r = chase_symlinks(p, temp, 0, &result);
142         assert_se(r > 0 && path_equal(result, q));
143         result = mfree(result);
144
145         /* Paths that contain repeated slashes */
146
147         p = strjoina(temp, "/slashslash");
148         assert_se(symlink("///usr///", p) >= 0);
149
150         r = chase_symlinks(p, NULL, 0, &result);
151         assert_se(r > 0);
152         assert_se(path_equal(result, "/usr"));
153         result = mfree(result);
154
155         r = chase_symlinks(p, temp, 0, &result);
156         assert_se(r > 0);
157         assert_se(path_equal(result, q));
158         result = mfree(result);
159
160         /* Paths using . */
161
162         r = chase_symlinks("/etc/./.././", NULL, 0, &result);
163         assert_se(r > 0);
164         assert_se(path_equal(result, "/"));
165         result = mfree(result);
166
167         r = chase_symlinks("/etc/./.././", "/etc", 0, &result);
168         assert_se(r > 0 && path_equal(result, "/etc"));
169         result = mfree(result);
170
171         r = chase_symlinks("/../.././//../../etc", NULL, 0, &result);
172         assert_se(r > 0);
173         assert_se(streq(result, "/etc"));
174         result = mfree(result);
175
176         r = chase_symlinks("/../.././//../../test-chase.fsldajfl", NULL, CHASE_NONEXISTENT, &result);
177         assert_se(r == 0);
178         assert_se(streq(result, "/test-chase.fsldajfl"));
179         result = mfree(result);
180
181         r = chase_symlinks("/../.././//../../etc", "/", CHASE_PREFIX_ROOT, &result);
182         assert_se(r > 0);
183         assert_se(streq(result, "/etc"));
184         result = mfree(result);
185
186         r = chase_symlinks("/../.././//../../test-chase.fsldajfl", "/", CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &result);
187         assert_se(r == 0);
188         assert_se(streq(result, "/test-chase.fsldajfl"));
189         result = mfree(result);
190
191         r = chase_symlinks("/etc/machine-id/foo", NULL, 0, &result);
192         assert_se(r == -ENOTDIR);
193         result = mfree(result);
194
195         /* Path that loops back to self */
196
197         p = strjoina(temp, "/recursive-symlink");
198         assert_se(symlink("recursive-symlink", p) >= 0);
199         r = chase_symlinks(p, NULL, 0, &result);
200         assert_se(r == -ELOOP);
201
202         /* Path which doesn't exist */
203
204         p = strjoina(temp, "/idontexist");
205         r = chase_symlinks(p, NULL, 0, &result);
206         assert_se(r == -ENOENT);
207
208         r = chase_symlinks(p, NULL, CHASE_NONEXISTENT, &result);
209         assert_se(r == 0);
210         assert_se(path_equal(result, p));
211         result = mfree(result);
212
213         p = strjoina(temp, "/idontexist/meneither");
214         r = chase_symlinks(p, NULL, 0, &result);
215         assert_se(r == -ENOENT);
216
217         r = chase_symlinks(p, NULL, CHASE_NONEXISTENT, &result);
218         assert_se(r == 0);
219         assert_se(path_equal(result, p));
220         result = mfree(result);
221
222         /* Path which doesn't exist, but contains weird stuff */
223
224         p = strjoina(temp, "/idontexist/..");
225         r = chase_symlinks(p, NULL, 0, &result);
226         assert_se(r == -ENOENT);
227
228         r = chase_symlinks(p, NULL, CHASE_NONEXISTENT, &result);
229         assert_se(r == -ENOENT);
230
231         p = strjoina(temp, "/target");
232         q = strjoina(temp, "/top");
233         assert_se(symlink(q, p) >= 0);
234         p = strjoina(temp, "/target/idontexist");
235         r = chase_symlinks(p, NULL, 0, &result);
236         assert_se(r == -ENOENT);
237
238         assert_se(rm_rf(temp, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
239 }
240
241 static void test_unlink_noerrno(void) {
242         char name[] = "/tmp/test-close_nointr.XXXXXX";
243         int fd;
244
245         fd = mkostemp_safe(name);
246         assert_se(fd >= 0);
247         assert_se(close_nointr(fd) >= 0);
248
249         {
250                 PROTECT_ERRNO;
251                 errno = -42;
252                 assert_se(unlink_noerrno(name) >= 0);
253                 assert_se(errno == -42);
254                 assert_se(unlink_noerrno(name) < 0);
255                 assert_se(errno == -42);
256         }
257 }
258
259 static void test_readlink_and_make_absolute(void) {
260         char tempdir[] = "/tmp/test-readlink_and_make_absolute";
261         char name[] = "/tmp/test-readlink_and_make_absolute/original";
262         char name2[] = "test-readlink_and_make_absolute/original";
263         char name_alias[] = "/tmp/test-readlink_and_make_absolute-alias";
264         char *r = NULL;
265         _cleanup_free_ char *pwd = NULL;
266
267         assert_se(mkdir_safe(tempdir, 0755, getuid(), getgid(), false) >= 0);
268         assert_se(touch(name) >= 0);
269
270         assert_se(symlink(name, name_alias) >= 0);
271         assert_se(readlink_and_make_absolute(name_alias, &r) >= 0);
272         assert_se(streq(r, name));
273         free(r);
274         assert_se(unlink(name_alias) >= 0);
275
276         assert_se(pwd = get_current_dir_name());
277
278         assert_se(chdir(tempdir) >= 0);
279         assert_se(symlink(name2, name_alias) >= 0);
280         assert_se(readlink_and_make_absolute(name_alias, &r) >= 0);
281         assert_se(streq(r, name));
282         free(r);
283         assert_se(unlink(name_alias) >= 0);
284
285         assert_se(chdir(pwd) >= 0);
286
287         assert_se(rm_rf(tempdir, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
288 }
289
290 static void test_get_files_in_directory(void) {
291         _cleanup_strv_free_ char **l = NULL, **t = NULL;
292
293         assert_se(get_files_in_directory("/tmp", &l) >= 0);
294         assert_se(get_files_in_directory(".", &t) >= 0);
295         assert_se(get_files_in_directory(".", NULL) >= 0);
296 }
297
298 #if 0 /// UNNEEDED by elogind
299 static void test_var_tmp(void) {
300         _cleanup_free_ char *tmpdir_backup = NULL, *temp_backup = NULL, *tmp_backup = NULL;
301         const char *tmp_dir = NULL, *t;
302
303         t = getenv("TMPDIR");
304         if (t) {
305                 tmpdir_backup = strdup(t);
306                 assert_se(tmpdir_backup);
307         }
308
309         t = getenv("TEMP");
310         if (t) {
311                 temp_backup = strdup(t);
312                 assert_se(temp_backup);
313         }
314
315         t = getenv("TMP");
316         if (t) {
317                 tmp_backup = strdup(t);
318                 assert_se(tmp_backup);
319         }
320
321         assert_se(unsetenv("TMPDIR") >= 0);
322         assert_se(unsetenv("TEMP") >= 0);
323         assert_se(unsetenv("TMP") >= 0);
324
325         assert_se(var_tmp_dir(&tmp_dir) >= 0);
326         assert_se(streq(tmp_dir, "/var/tmp"));
327
328         assert_se(setenv("TMPDIR", "/tmp", true) >= 0);
329         assert_se(streq(getenv("TMPDIR"), "/tmp"));
330
331         assert_se(var_tmp_dir(&tmp_dir) >= 0);
332         assert_se(streq(tmp_dir, "/tmp"));
333
334         assert_se(setenv("TMPDIR", "/88_does_not_exist_88", true) >= 0);
335         assert_se(streq(getenv("TMPDIR"), "/88_does_not_exist_88"));
336
337         assert_se(var_tmp_dir(&tmp_dir) >= 0);
338         assert_se(streq(tmp_dir, "/var/tmp"));
339
340         if (tmpdir_backup)  {
341                 assert_se(setenv("TMPDIR", tmpdir_backup, true) >= 0);
342                 assert_se(streq(getenv("TMPDIR"), tmpdir_backup));
343         }
344
345         if (temp_backup)  {
346                 assert_se(setenv("TEMP", temp_backup, true) >= 0);
347                 assert_se(streq(getenv("TEMP"), temp_backup));
348         }
349
350         if (tmp_backup)  {
351                 assert_se(setenv("TMP", tmp_backup, true) >= 0);
352                 assert_se(streq(getenv("TMP"), tmp_backup));
353         }
354 }
355 #endif // 0
356
357 static void test_dot_or_dot_dot(void) {
358         assert_se(!dot_or_dot_dot(NULL));
359         assert_se(!dot_or_dot_dot(""));
360         assert_se(!dot_or_dot_dot("xxx"));
361         assert_se(dot_or_dot_dot("."));
362         assert_se(dot_or_dot_dot(".."));
363         assert_se(!dot_or_dot_dot(".foo"));
364         assert_se(!dot_or_dot_dot("..foo"));
365 }
366
367 #if 0 /// Uses functions that elogind does not need
368 static void test_access_fd(void) {
369         _cleanup_(rmdir_and_freep) char *p = NULL;
370         _cleanup_close_ int fd = -1;
371
372         assert_se(mkdtemp_malloc("/tmp/access-fd.XXXXXX", &p) >= 0);
373
374         fd = open(p, O_RDONLY|O_DIRECTORY|O_CLOEXEC);
375         assert_se(fd >= 0);
376
377         assert_se(access_fd(fd, R_OK) >= 0);
378         assert_se(access_fd(fd, F_OK) >= 0);
379         assert_se(access_fd(fd, W_OK) >= 0);
380
381         assert_se(fchmod(fd, 0000) >= 0);
382
383         assert_se(access_fd(fd, F_OK) >= 0);
384
385         if (geteuid() == 0) {
386                 assert_se(access_fd(fd, R_OK) >= 0);
387                 assert_se(access_fd(fd, W_OK) >= 0);
388         } else {
389                 assert_se(access_fd(fd, R_OK) == -EACCES);
390                 assert_se(access_fd(fd, W_OK) == -EACCES);
391         }
392 }
393 #endif // 0
394
395 int main(int argc, char *argv[]) {
396         test_unlink_noerrno();
397         test_get_files_in_directory();
398         test_readlink_and_make_absolute();
399 #if 0 /// UNNEEDED by elogind
400         test_var_tmp();
401 #endif // 0
402         test_chase_symlinks();
403         test_dot_or_dot_dot();
404 #if 0 /// Uses functions that elogind does not need
405         test_access_fd();
406 #endif // 0
407
408         return 0;
409 }