]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/test/test-fs-util.c
Merge pull request #7530 from poettering/uid-gid-fixes
[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
95f35ccc
YW
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
c4f4fce7 191 r = chase_symlinks("/etc/machine-id/foo", NULL, 0, &result);
d944dc95 192 assert_se(r == -ENOTDIR);
b12d25a8 193 result = mfree(result);
d944dc95 194
df878e68
ZJS
195 /* Path that loops back to self */
196
d944dc95
LP
197 p = strjoina(temp, "/recursive-symlink");
198 assert_se(symlink("recursive-symlink", p) >= 0);
c4f4fce7 199 r = chase_symlinks(p, NULL, 0, &result);
d944dc95
LP
200 assert_se(r == -ELOOP);
201
a9fb0867
LP
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
cb638b5e 208 r = chase_symlinks(p, NULL, CHASE_NONEXISTENT, &result);
a9fb0867
LP
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
cb638b5e 217 r = chase_symlinks(p, NULL, CHASE_NONEXISTENT, &result);
a9fb0867
LP
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
cb638b5e 228 r = chase_symlinks(p, NULL, CHASE_NONEXISTENT, &result);
a9fb0867
LP
229 assert_se(r == -ENOENT);
230
877777d7
CCW
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
d944dc95
LP
238 assert_se(rm_rf(temp, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
239}
240
c270684a
RC
241static void test_unlink_noerrno(void) {
242 char name[] = "/tmp/test-close_nointr.XXXXXX";
243 int fd;
244
646853bd 245 fd = mkostemp_safe(name);
c270684a
RC
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
259static 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;
cd76d4c2 265 _cleanup_free_ char *pwd = NULL;
c270684a 266
c31ad024 267 assert_se(mkdir_safe(tempdir, 0755, getuid(), getgid(), false) >= 0);
c270684a
RC
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
cd76d4c2
YW
276 assert_se(pwd = get_current_dir_name());
277
c270684a
RC
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
cd76d4c2
YW
285 assert_se(chdir(pwd) >= 0);
286
c270684a
RC
287 assert_se(rm_rf(tempdir, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
288}
289
290static 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
34a8f081 298static void test_var_tmp(void) {
4245eb50 299 _cleanup_free_ char *tmpdir_backup = NULL, *temp_backup = NULL, *tmp_backup = NULL;
992e8f22 300 const char *tmp_dir = NULL, *t;
34a8f081 301
992e8f22
LP
302 t = getenv("TMPDIR");
303 if (t) {
304 tmpdir_backup = strdup(t);
305 assert_se(tmpdir_backup);
306 }
34a8f081 307
4245eb50
MAP
308 t = getenv("TEMP");
309 if (t) {
310 temp_backup = strdup(t);
311 assert_se(temp_backup);
312 }
313
314 t = getenv("TMP");
315 if (t) {
316 tmp_backup = strdup(t);
317 assert_se(tmp_backup);
318 }
319
85e55d14
YW
320 assert_se(unsetenv("TMPDIR") >= 0);
321 assert_se(unsetenv("TEMP") >= 0);
322 assert_se(unsetenv("TMP") >= 0);
34a8f081 323
992e8f22
LP
324 assert_se(var_tmp_dir(&tmp_dir) >= 0);
325 assert_se(streq(tmp_dir, "/var/tmp"));
34a8f081 326
992e8f22
LP
327 assert_se(setenv("TMPDIR", "/tmp", true) >= 0);
328 assert_se(streq(getenv("TMPDIR"), "/tmp"));
34a8f081 329
992e8f22
LP
330 assert_se(var_tmp_dir(&tmp_dir) >= 0);
331 assert_se(streq(tmp_dir, "/tmp"));
34a8f081 332
992e8f22
LP
333 assert_se(setenv("TMPDIR", "/88_does_not_exist_88", true) >= 0);
334 assert_se(streq(getenv("TMPDIR"), "/88_does_not_exist_88"));
34a8f081 335
992e8f22
LP
336 assert_se(var_tmp_dir(&tmp_dir) >= 0);
337 assert_se(streq(tmp_dir, "/var/tmp"));
34a8f081 338
992e8f22
LP
339 if (tmpdir_backup) {
340 assert_se(setenv("TMPDIR", tmpdir_backup, true) >= 0);
341 assert_se(streq(getenv("TMPDIR"), tmpdir_backup));
34a8f081 342 }
4245eb50
MAP
343
344 if (temp_backup) {
345 assert_se(setenv("TEMP", temp_backup, true) >= 0);
346 assert_se(streq(getenv("TEMP"), temp_backup));
347 }
348
349 if (tmp_backup) {
350 assert_se(setenv("TMP", tmp_backup, true) >= 0);
351 assert_se(streq(getenv("TMP"), tmp_backup));
352 }
34a8f081
OW
353}
354
49bfc877
LP
355static void test_dot_or_dot_dot(void) {
356 assert_se(!dot_or_dot_dot(NULL));
357 assert_se(!dot_or_dot_dot(""));
358 assert_se(!dot_or_dot_dot("xxx"));
359 assert_se(dot_or_dot_dot("."));
360 assert_se(dot_or_dot_dot(".."));
361 assert_se(!dot_or_dot_dot(".foo"));
362 assert_se(!dot_or_dot_dot("..foo"));
363}
364
57a4359e
LP
365static void test_access_fd(void) {
366 _cleanup_(rmdir_and_freep) char *p = NULL;
367 _cleanup_close_ int fd = -1;
368
369 assert_se(mkdtemp_malloc("/tmp/access-fd.XXXXXX", &p) >= 0);
370
371 fd = open(p, O_RDONLY|O_DIRECTORY|O_CLOEXEC);
372 assert_se(fd >= 0);
373
374 assert_se(access_fd(fd, R_OK) >= 0);
375 assert_se(access_fd(fd, F_OK) >= 0);
376 assert_se(access_fd(fd, W_OK) >= 0);
377
378 assert_se(fchmod(fd, 0000) >= 0);
379
380 assert_se(access_fd(fd, F_OK) >= 0);
381
382 if (geteuid() == 0) {
383 assert_se(access_fd(fd, R_OK) >= 0);
384 assert_se(access_fd(fd, W_OK) >= 0);
385 } else {
386 assert_se(access_fd(fd, R_OK) == -EACCES);
387 assert_se(access_fd(fd, W_OK) == -EACCES);
388 }
389}
390
c270684a
RC
391int main(int argc, char *argv[]) {
392 test_unlink_noerrno();
c270684a 393 test_get_files_in_directory();
496c486f 394 test_readlink_and_make_absolute();
34a8f081 395 test_var_tmp();
d944dc95 396 test_chase_symlinks();
49bfc877 397 test_dot_or_dot_dot();
57a4359e 398 test_access_fd();
c270684a
RC
399
400 return 0;
401}