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