]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/test/test-fs-util.c
util-lib: use trailing slash in chase_symlinks, fd_is_mount_point, path_is_mount_point
[thirdparty/systemd.git] / src / test / test-fs-util.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
c270684a
RC
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"
c270684a 24#include "fd-util.h"
d944dc95 25#include "fileio.h"
c270684a
RC
26#include "fs-util.h"
27#include "macro.h"
28#include "mkdir.h"
d944dc95 29#include "path-util.h"
c270684a
RC
30#include "rm-rf.h"
31#include "string-util.h"
32#include "strv.h"
33#include "util.h"
34
d944dc95
LP
35static void test_chase_symlinks(void) {
36 _cleanup_free_ char *result = NULL;
37 char temp[] = "/tmp/test-chase.XXXXXX";
b12d25a8 38 const char *top, *p, *pslash, *q, *qslash;
d944dc95
LP
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
df878e68
ZJS
64 /* Paths that use symlinks underneath the "root" */
65
c4f4fce7 66 r = chase_symlinks(p, NULL, 0, &result);
a9fb0867 67 assert_se(r > 0);
d944dc95 68 assert_se(path_equal(result, "/usr"));
b12d25a8 69 result = mfree(result);
d944dc95 70
b12d25a8
ZJS
71 pslash = strjoina(p, "/");
72 r = chase_symlinks(pslash, NULL, 0, &result);
73 assert_se(r > 0);
74 assert_se(path_equal(result, "/usr/"));
d944dc95 75 result = mfree(result);
b12d25a8 76
c4f4fce7 77 r = chase_symlinks(p, temp, 0, &result);
d944dc95
LP
78 assert_se(r == -ENOENT);
79
b12d25a8
ZJS
80 r = chase_symlinks(pslash, temp, 0, &result);
81 assert_se(r == -ENOENT);
82
d944dc95 83 q = strjoina(temp, "/usr");
a9fb0867 84
cb638b5e 85 r = chase_symlinks(p, temp, CHASE_NONEXISTENT, &result);
a9fb0867
LP
86 assert_se(r == 0);
87 assert_se(path_equal(result, q));
b12d25a8 88 result = mfree(result);
a9fb0867 89
b12d25a8 90 qslash = strjoina(q, "/");
d944dc95 91
b12d25a8
ZJS
92 r = chase_symlinks(pslash, temp, CHASE_NONEXISTENT, &result);
93 assert_se(r == 0);
94 assert_se(path_equal(result, qslash));
f4b85a0f 95 result = mfree(result);
b12d25a8
ZJS
96
97 assert_se(mkdir(q, 0700) >= 0);
98
c4f4fce7 99 r = chase_symlinks(p, temp, 0, &result);
a9fb0867 100 assert_se(r > 0);
d944dc95 101 assert_se(path_equal(result, q));
b12d25a8
ZJS
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);
d944dc95
LP
108
109 p = strjoina(temp, "/slash");
110 assert_se(symlink("/", p) >= 0);
111
c4f4fce7 112 r = chase_symlinks(p, NULL, 0, &result);
a9fb0867 113 assert_se(r > 0);
d944dc95 114 assert_se(path_equal(result, "/"));
d944dc95 115 result = mfree(result);
b12d25a8 116
c4f4fce7 117 r = chase_symlinks(p, temp, 0, &result);
a9fb0867 118 assert_se(r > 0);
d944dc95 119 assert_se(path_equal(result, temp));
b12d25a8 120 result = mfree(result);
d944dc95 121
df878e68
ZJS
122 /* Paths that would "escape" outside of the "root" */
123
124 p = strjoina(temp, "/6dots");
125 assert_se(symlink("../../..", p) >= 0);
126
c4f4fce7 127 r = chase_symlinks(p, temp, 0, &result);
a9fb0867 128 assert_se(r > 0 && path_equal(result, temp));
b12d25a8 129 result = mfree(result);
df878e68
ZJS
130
131 p = strjoina(temp, "/6dotsusr");
132 assert_se(symlink("../../../usr", p) >= 0);
133
c4f4fce7 134 r = chase_symlinks(p, temp, 0, &result);
a9fb0867 135 assert_se(r > 0 && path_equal(result, q));
b12d25a8 136 result = mfree(result);
df878e68
ZJS
137
138 p = strjoina(temp, "/top/8dotsusr");
139 assert_se(symlink("../../../../usr", p) >= 0);
140
c4f4fce7 141 r = chase_symlinks(p, temp, 0, &result);
a9fb0867 142 assert_se(r > 0 && path_equal(result, q));
b12d25a8 143 result = mfree(result);
df878e68
ZJS
144
145 /* Paths that contain repeated slashes */
146
d944dc95
LP
147 p = strjoina(temp, "/slashslash");
148 assert_se(symlink("///usr///", p) >= 0);
149
c4f4fce7 150 r = chase_symlinks(p, NULL, 0, &result);
a9fb0867 151 assert_se(r > 0);
d944dc95 152 assert_se(path_equal(result, "/usr"));
d944dc95 153 result = mfree(result);
b12d25a8 154
c4f4fce7 155 r = chase_symlinks(p, temp, 0, &result);
a9fb0867 156 assert_se(r > 0);
d944dc95 157 assert_se(path_equal(result, q));
b12d25a8 158 result = mfree(result);
d944dc95 159
df878e68
ZJS
160 /* Paths using . */
161
c4f4fce7 162 r = chase_symlinks("/etc/./.././", NULL, 0, &result);
a9fb0867 163 assert_se(r > 0);
d944dc95 164 assert_se(path_equal(result, "/"));
d944dc95 165 result = mfree(result);
b12d25a8 166
c4f4fce7 167 r = chase_symlinks("/etc/./.././", "/etc", 0, &result);
a9fb0867 168 assert_se(r > 0 && path_equal(result, "/etc"));
d944dc95 169 result = mfree(result);
b12d25a8 170
c4f4fce7 171 r = chase_symlinks("/etc/machine-id/foo", NULL, 0, &result);
d944dc95 172 assert_se(r == -ENOTDIR);
b12d25a8 173 result = mfree(result);
d944dc95 174
df878e68
ZJS
175 /* Path that loops back to self */
176
d944dc95
LP
177 p = strjoina(temp, "/recursive-symlink");
178 assert_se(symlink("recursive-symlink", p) >= 0);
c4f4fce7 179 r = chase_symlinks(p, NULL, 0, &result);
d944dc95
LP
180 assert_se(r == -ELOOP);
181
a9fb0867
LP
182 /* Path which doesn't exist */
183
184 p = strjoina(temp, "/idontexist");
185 r = chase_symlinks(p, NULL, 0, &result);
186 assert_se(r == -ENOENT);
187
cb638b5e 188 r = chase_symlinks(p, NULL, CHASE_NONEXISTENT, &result);
a9fb0867
LP
189 assert_se(r == 0);
190 assert_se(path_equal(result, p));
191 result = mfree(result);
192
193 p = strjoina(temp, "/idontexist/meneither");
194 r = chase_symlinks(p, NULL, 0, &result);
195 assert_se(r == -ENOENT);
196
cb638b5e 197 r = chase_symlinks(p, NULL, CHASE_NONEXISTENT, &result);
a9fb0867
LP
198 assert_se(r == 0);
199 assert_se(path_equal(result, p));
200 result = mfree(result);
201
202 /* Path which doesn't exist, but contains weird stuff */
203
204 p = strjoina(temp, "/idontexist/..");
205 r = chase_symlinks(p, NULL, 0, &result);
206 assert_se(r == -ENOENT);
207
cb638b5e 208 r = chase_symlinks(p, NULL, CHASE_NONEXISTENT, &result);
a9fb0867
LP
209 assert_se(r == -ENOENT);
210
877777d7
CCW
211 p = strjoina(temp, "/target");
212 q = strjoina(temp, "/top");
213 assert_se(symlink(q, p) >= 0);
214 p = strjoina(temp, "/target/idontexist");
215 r = chase_symlinks(p, NULL, 0, &result);
216 assert_se(r == -ENOENT);
217
d944dc95
LP
218 assert_se(rm_rf(temp, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
219}
220
c270684a
RC
221static void test_unlink_noerrno(void) {
222 char name[] = "/tmp/test-close_nointr.XXXXXX";
223 int fd;
224
646853bd 225 fd = mkostemp_safe(name);
c270684a
RC
226 assert_se(fd >= 0);
227 assert_se(close_nointr(fd) >= 0);
228
229 {
230 PROTECT_ERRNO;
231 errno = -42;
232 assert_se(unlink_noerrno(name) >= 0);
233 assert_se(errno == -42);
234 assert_se(unlink_noerrno(name) < 0);
235 assert_se(errno == -42);
236 }
237}
238
239static void test_readlink_and_make_absolute(void) {
240 char tempdir[] = "/tmp/test-readlink_and_make_absolute";
241 char name[] = "/tmp/test-readlink_and_make_absolute/original";
242 char name2[] = "test-readlink_and_make_absolute/original";
243 char name_alias[] = "/tmp/test-readlink_and_make_absolute-alias";
244 char *r = NULL;
245
c31ad024 246 assert_se(mkdir_safe(tempdir, 0755, getuid(), getgid(), false) >= 0);
c270684a
RC
247 assert_se(touch(name) >= 0);
248
249 assert_se(symlink(name, name_alias) >= 0);
250 assert_se(readlink_and_make_absolute(name_alias, &r) >= 0);
251 assert_se(streq(r, name));
252 free(r);
253 assert_se(unlink(name_alias) >= 0);
254
255 assert_se(chdir(tempdir) >= 0);
256 assert_se(symlink(name2, name_alias) >= 0);
257 assert_se(readlink_and_make_absolute(name_alias, &r) >= 0);
258 assert_se(streq(r, name));
259 free(r);
260 assert_se(unlink(name_alias) >= 0);
261
262 assert_se(rm_rf(tempdir, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
263}
264
265static void test_get_files_in_directory(void) {
266 _cleanup_strv_free_ char **l = NULL, **t = NULL;
267
268 assert_se(get_files_in_directory("/tmp", &l) >= 0);
269 assert_se(get_files_in_directory(".", &t) >= 0);
270 assert_se(get_files_in_directory(".", NULL) >= 0);
271}
272
34a8f081 273static void test_var_tmp(void) {
4245eb50 274 _cleanup_free_ char *tmpdir_backup = NULL, *temp_backup = NULL, *tmp_backup = NULL;
992e8f22 275 const char *tmp_dir = NULL, *t;
34a8f081 276
992e8f22
LP
277 t = getenv("TMPDIR");
278 if (t) {
279 tmpdir_backup = strdup(t);
280 assert_se(tmpdir_backup);
281 }
34a8f081 282
4245eb50
MAP
283 t = getenv("TEMP");
284 if (t) {
285 temp_backup = strdup(t);
286 assert_se(temp_backup);
287 }
288
289 t = getenv("TMP");
290 if (t) {
291 tmp_backup = strdup(t);
292 assert_se(tmp_backup);
293 }
294
85e55d14
YW
295 assert_se(unsetenv("TMPDIR") >= 0);
296 assert_se(unsetenv("TEMP") >= 0);
297 assert_se(unsetenv("TMP") >= 0);
34a8f081 298
992e8f22
LP
299 assert_se(var_tmp_dir(&tmp_dir) >= 0);
300 assert_se(streq(tmp_dir, "/var/tmp"));
34a8f081 301
992e8f22
LP
302 assert_se(setenv("TMPDIR", "/tmp", true) >= 0);
303 assert_se(streq(getenv("TMPDIR"), "/tmp"));
34a8f081 304
992e8f22
LP
305 assert_se(var_tmp_dir(&tmp_dir) >= 0);
306 assert_se(streq(tmp_dir, "/tmp"));
34a8f081 307
992e8f22
LP
308 assert_se(setenv("TMPDIR", "/88_does_not_exist_88", true) >= 0);
309 assert_se(streq(getenv("TMPDIR"), "/88_does_not_exist_88"));
34a8f081 310
992e8f22
LP
311 assert_se(var_tmp_dir(&tmp_dir) >= 0);
312 assert_se(streq(tmp_dir, "/var/tmp"));
34a8f081 313
992e8f22
LP
314 if (tmpdir_backup) {
315 assert_se(setenv("TMPDIR", tmpdir_backup, true) >= 0);
316 assert_se(streq(getenv("TMPDIR"), tmpdir_backup));
34a8f081 317 }
4245eb50
MAP
318
319 if (temp_backup) {
320 assert_se(setenv("TEMP", temp_backup, true) >= 0);
321 assert_se(streq(getenv("TEMP"), temp_backup));
322 }
323
324 if (tmp_backup) {
325 assert_se(setenv("TMP", tmp_backup, true) >= 0);
326 assert_se(streq(getenv("TMP"), tmp_backup));
327 }
34a8f081
OW
328}
329
49bfc877
LP
330static void test_dot_or_dot_dot(void) {
331 assert_se(!dot_or_dot_dot(NULL));
332 assert_se(!dot_or_dot_dot(""));
333 assert_se(!dot_or_dot_dot("xxx"));
334 assert_se(dot_or_dot_dot("."));
335 assert_se(dot_or_dot_dot(".."));
336 assert_se(!dot_or_dot_dot(".foo"));
337 assert_se(!dot_or_dot_dot("..foo"));
338}
339
57a4359e
LP
340static void test_access_fd(void) {
341 _cleanup_(rmdir_and_freep) char *p = NULL;
342 _cleanup_close_ int fd = -1;
343
344 assert_se(mkdtemp_malloc("/tmp/access-fd.XXXXXX", &p) >= 0);
345
346 fd = open(p, O_RDONLY|O_DIRECTORY|O_CLOEXEC);
347 assert_se(fd >= 0);
348
349 assert_se(access_fd(fd, R_OK) >= 0);
350 assert_se(access_fd(fd, F_OK) >= 0);
351 assert_se(access_fd(fd, W_OK) >= 0);
352
353 assert_se(fchmod(fd, 0000) >= 0);
354
355 assert_se(access_fd(fd, F_OK) >= 0);
356
357 if (geteuid() == 0) {
358 assert_se(access_fd(fd, R_OK) >= 0);
359 assert_se(access_fd(fd, W_OK) >= 0);
360 } else {
361 assert_se(access_fd(fd, R_OK) == -EACCES);
362 assert_se(access_fd(fd, W_OK) == -EACCES);
363 }
364}
365
c270684a
RC
366int main(int argc, char *argv[]) {
367 test_unlink_noerrno();
c270684a 368 test_get_files_in_directory();
496c486f 369 test_readlink_and_make_absolute();
34a8f081 370 test_var_tmp();
d944dc95 371 test_chase_symlinks();
49bfc877 372 test_dot_or_dot_dot();
57a4359e 373 test_access_fd();
c270684a
RC
374
375 return 0;
376}