tools/llvm: Do not build with symbols
[minix3.git] / external / bsd / kyua-testers / dist / fs_test.c
blob4c6f6c36930dbde0472d305edcdd52b7aeed1db3
1 // Copyright 2012 Google Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above copyright
11 // notice, this list of conditions and the following disclaimer in the
12 // documentation and/or other materials provided with the distribution.
13 // * Neither the name of Google Inc. nor the names of its contributors
14 // may be used to endorse or promote products derived from this software
15 // without specific prior written permission.
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include "fs.h"
31 #include <sys/stat.h>
32 #include <sys/wait.h>
34 #include <assert.h>
35 #include <dirent.h>
36 #include <err.h>
37 #include <errno.h>
38 #include <signal.h>
39 #include <stdbool.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <unistd.h>
45 #include <atf-c.h>
47 #include "error.h"
50 static void run_mount_tmpfs(const char*) KYUA_DEFS_NORETURN;
53 /// Operating systems recognized by the code below.
54 enum os_type {
55 os_unsupported = 0,
56 os_freebsd,
57 os_linux,
58 os_netbsd,
59 os_sunos,
63 /// The current operating system.
64 static enum os_type current_os =
65 #if defined(__FreeBSD__)
66 os_freebsd
67 #elif defined(__linux__)
68 os_linux
69 #elif defined(__NetBSD__)
70 os_netbsd
71 #elif defined(__SunOS__)
72 os_sunos
73 #else
74 os_unsupported
75 #endif
79 /// Checks if a directory entry exists and matches a specific type.
80 ///
81 /// \param dir The directory in which to look for the entry.
82 /// \param name The name of the entry to look up.
83 /// \param expected_type The expected type of the file as given by dir(5).
84 ///
85 /// \return True if the entry exists and matches the given type; false
86 /// otherwise.
87 static bool
88 lookup(const char* dir, const char* name, const int expected_type)
90 DIR* dirp = opendir(dir);
91 ATF_REQUIRE(dirp != NULL);
93 bool found = false;
94 struct dirent* dp;
95 while (!found && (dp = readdir(dirp)) != NULL) {
96 if (strcmp(dp->d_name, name) == 0 &&
97 dp->d_type == expected_type) {
98 found = true;
101 closedir(dirp);
102 return found;
106 /// Executes 'mount -t tmpfs' (or a similar variant).
108 /// This function must be called from a subprocess, as it never returns.
110 /// \param mount_point Location on which to mount a tmpfs.
111 static void
112 run_mount_tmpfs(const char* mount_point)
114 const char* mount_args[16];
116 size_t last = 0;
117 switch (current_os) {
118 case os_freebsd:
119 mount_args[last++] = "mdmfs";
120 mount_args[last++] = "-s16m";
121 mount_args[last++] = "md";
122 mount_args[last++] = mount_point;
123 break;
125 case os_linux:
126 mount_args[last++] = "mount";
127 mount_args[last++] = "-ttmpfs";
128 mount_args[last++] = "tmpfs";
129 mount_args[last++] = mount_point;
130 break;
132 case os_netbsd:
133 mount_args[last++] = "mount";
134 mount_args[last++] = "-ttmpfs";
135 mount_args[last++] = "tmpfs";
136 mount_args[last++] = mount_point;
137 break;
139 case os_sunos:
140 mount_args[last++] = "mount";
141 mount_args[last++] = "-Ftmpfs";
142 mount_args[last++] = "tmpfs";
143 mount_args[last++] = mount_point;
144 break;
146 default:
147 err(123, "Don't know how to mount a file system for testing "
148 "purposes");
150 mount_args[last] = NULL;
152 const char** arg;
153 printf("Mounting tmpfs onto %s with:", mount_point);
154 for (arg = &mount_args[0]; *arg != NULL; arg++)
155 printf(" %s", *arg);
156 printf("\n");
158 const int ret = execvp(mount_args[0], KYUA_DEFS_UNCONST(mount_args));
159 assert(ret == -1);
160 err(EXIT_FAILURE, "Failed to exec %s", mount_args[0]);
164 /// Mounts a temporary file system.
166 /// This is only provided for testing purposes. The mounted file system
167 /// contains no valuable data.
169 /// Note that the calling test case is skipped if the current operating system
170 /// is not supported.
172 /// \param mount_point The path on which the file system will be mounted.
173 static void
174 mount_tmpfs(const char* mount_point)
176 // SunOS's mount(8) requires paths to be absolute. To err on the side of
177 // caution, let's make it absolute in all cases.
178 //const fspath abs_mount_point = mount_point.is_absolute() ?
179 // mount_point : mount_point.to_absolute();
181 pid_t pid = fork();
182 ATF_REQUIRE(pid != -1);
183 if (pid == 0)
184 run_mount_tmpfs(mount_point);
185 int status;
186 ATF_REQUIRE(waitpid(pid, &status, 0) != -1);
187 ATF_REQUIRE(WIFEXITED(status));
188 if (WEXITSTATUS(status) == 123)
189 atf_tc_skip("Don't know how to mount a file system for testing "
190 "purposes");
191 else
192 ATF_REQUIRE_EQ(EXIT_SUCCESS, WEXITSTATUS(status));
196 static bool
197 lchmod_fails(void)
199 ATF_REQUIRE(mkdir("test", 0755) != -1);
200 return lchmod("test", 0700) == -1 && chmod("test", 0700) != -1;
204 ATF_TC_WITHOUT_HEAD(cleanup__file);
205 ATF_TC_BODY(cleanup__file, tc)
207 atf_utils_create_file("root", "%s", "");
208 ATF_REQUIRE(lookup(".", "root", DT_REG));
209 ATF_REQUIRE(!kyua_error_is_set(kyua_fs_cleanup("root")));
210 ATF_REQUIRE(!lookup(".", "root", DT_REG));
214 ATF_TC_WITHOUT_HEAD(cleanup__subdir__empty);
215 ATF_TC_BODY(cleanup__subdir__empty, tc)
217 ATF_REQUIRE(mkdir("root", 0755) != -1);
218 ATF_REQUIRE(lookup(".", "root", DT_DIR));
219 ATF_REQUIRE(!kyua_error_is_set(kyua_fs_cleanup("root")));
220 ATF_REQUIRE(!lookup(".", "root", DT_DIR));
224 ATF_TC_WITHOUT_HEAD(cleanup__subdir__files_and_directories);
225 ATF_TC_BODY(cleanup__subdir__files_and_directories, tc)
227 ATF_REQUIRE(mkdir("root", 0755) != -1);
228 atf_utils_create_file("root/.hidden_file", "%s", "");
229 ATF_REQUIRE(mkdir("root/.hidden_dir", 0755) != -1);
230 atf_utils_create_file("root/.hidden_dir/a", "%s", "");
231 atf_utils_create_file("root/file", "%s", "");
232 atf_utils_create_file("root/with spaces", "%s", "");
233 ATF_REQUIRE(mkdir("root/dir1", 0755) != -1);
234 ATF_REQUIRE(mkdir("root/dir1/dir2", 0755) != -1);
235 atf_utils_create_file("root/dir1/dir2/file", "%s", "");
236 ATF_REQUIRE(mkdir("root/dir1/dir3", 0755) != -1);
237 ATF_REQUIRE(lookup(".", "root", DT_DIR));
238 ATF_REQUIRE(!kyua_error_is_set(kyua_fs_cleanup("root")));
239 ATF_REQUIRE(!lookup(".", "root", DT_DIR));
243 ATF_TC_WITHOUT_HEAD(cleanup__subdir__unprotect_regular);
244 ATF_TC_BODY(cleanup__subdir__unprotect_regular, tc)
246 ATF_REQUIRE(mkdir("root", 0755) != -1);
247 ATF_REQUIRE(mkdir("root/dir1", 0755) != -1);
248 ATF_REQUIRE(mkdir("root/dir1/dir2", 0755) != -1);
249 atf_utils_create_file("root/dir1/dir2/file", "%s", "");
250 ATF_REQUIRE(chmod("root/dir1/dir2/file", 0000) != -1);
251 ATF_REQUIRE(chmod("root/dir1/dir2", 0000) != -1);
252 ATF_REQUIRE(chmod("root/dir1", 0000) != -1);
253 ATF_REQUIRE(!kyua_error_is_set(kyua_fs_cleanup("root")));
254 ATF_REQUIRE(!lookup(".", "root", DT_DIR));
258 ATF_TC(cleanup__subdir__unprotect_symlink);
259 ATF_TC_HEAD(cleanup__subdir__unprotect_symlink, tc)
261 atf_tc_set_md_var(tc, "require.progs", "/bin/ls");
262 // We are ensuring that chmod is not run on the target of a symlink, so
263 // we cannot be root (nor we don't want to, to prevent unprotecting a
264 // system file!).
265 atf_tc_set_md_var(tc, "require.user", "unprivileged");
267 ATF_TC_BODY(cleanup__subdir__unprotect_symlink, tc)
269 ATF_REQUIRE(mkdir("root", 0755) != -1);
270 ATF_REQUIRE(mkdir("root/dir1", 0755) != -1);
271 ATF_REQUIRE(symlink("/bin/ls", "root/dir1/ls") != -1);
272 ATF_REQUIRE(chmod("root/dir1", 0555) != -1);
273 ATF_REQUIRE(!kyua_error_is_set(kyua_fs_cleanup("root")));
274 ATF_REQUIRE(!lookup(".", "root", DT_DIR));
278 ATF_TC_WITHOUT_HEAD(cleanup__subdir__links);
279 ATF_TC_BODY(cleanup__subdir__links, tc)
281 ATF_REQUIRE(mkdir("root", 0755) != -1);
282 ATF_REQUIRE(mkdir("root/dir1", 0755) != -1);
283 ATF_REQUIRE(symlink("../../root", "root/dir1/loop") != -1);
284 ATF_REQUIRE(symlink("non-existent", "root/missing") != -1);
285 ATF_REQUIRE(lookup(".", "root", DT_DIR));
286 kyua_error_t error = kyua_fs_cleanup("root");
287 if (kyua_error_is_set(error)) {
288 if (lchmod_fails())
289 atf_tc_expect_fail("lchmod(2) is not implemented in your system");
290 kyua_error_free(error);
291 atf_tc_fail("kyua_fs_cleanup returned an error");
293 ATF_REQUIRE(!lookup(".", "root", DT_DIR));
297 ATF_TC(cleanup__mount_point__simple);
298 ATF_TC_HEAD(cleanup__mount_point__simple, tc)
300 atf_tc_set_md_var(tc, "require.user", "root");
302 ATF_TC_BODY(cleanup__mount_point__simple, tc)
304 ATF_REQUIRE(mkdir("root", 0755) != -1);
305 ATF_REQUIRE(mkdir("root/dir1", 0755) != -1);
306 atf_utils_create_file("root/zz", "%s", "");
307 mount_tmpfs("root/dir1");
308 ATF_REQUIRE(!kyua_error_is_set(kyua_fs_cleanup("root")));
309 ATF_REQUIRE(!lookup(".", "root", DT_DIR));
313 ATF_TC(cleanup__mount_point__overlayed);
314 ATF_TC_HEAD(cleanup__mount_point__overlayed, tc)
316 atf_tc_set_md_var(tc, "require.user", "root");
318 ATF_TC_BODY(cleanup__mount_point__overlayed, tc)
320 ATF_REQUIRE(mkdir("root", 0755) != -1);
321 ATF_REQUIRE(mkdir("root/dir1", 0755) != -1);
322 atf_utils_create_file("root/zz", "%s", "");
323 mount_tmpfs("root/dir1");
324 mount_tmpfs("root/dir1");
325 ATF_REQUIRE(!kyua_error_is_set(kyua_fs_cleanup("root")));
326 ATF_REQUIRE(!lookup(".", "root", DT_DIR));
330 ATF_TC(cleanup__mount_point__nested);
331 ATF_TC_HEAD(cleanup__mount_point__nested, tc)
333 atf_tc_set_md_var(tc, "require.user", "root");
335 ATF_TC_BODY(cleanup__mount_point__nested, tc)
337 ATF_REQUIRE(mkdir("root", 0755) != -1);
338 ATF_REQUIRE(mkdir("root/dir1", 0755) != -1);
339 ATF_REQUIRE(mkdir("root/dir1/dir2", 0755) != -1);
340 ATF_REQUIRE(mkdir("root/dir3", 0755) != -1);
341 mount_tmpfs("root/dir1/dir2");
342 mount_tmpfs("root/dir3");
343 ATF_REQUIRE(mkdir("root/dir1/dir2/dir4", 0755) != -1);
344 mount_tmpfs("root/dir1/dir2/dir4");
345 ATF_REQUIRE(mkdir("root/dir1/dir2/not-mount-point", 0755) != -1);
346 ATF_REQUIRE(!kyua_error_is_set(kyua_fs_cleanup("root")));
347 ATF_REQUIRE(!lookup(".", "root", DT_DIR));
351 ATF_TC(cleanup__mount_point__links);
352 ATF_TC_HEAD(cleanup__mount_point__links, tc)
354 atf_tc_set_md_var(tc, "require.user", "root");
356 ATF_TC_BODY(cleanup__mount_point__links, tc)
358 ATF_REQUIRE(mkdir("root", 0755) != -1);
359 ATF_REQUIRE(mkdir("root/dir1", 0755) != -1);
360 ATF_REQUIRE(mkdir("root/dir3", 0755) != -1);
361 mount_tmpfs("root/dir1");
362 ATF_REQUIRE(symlink("../dir3", "root/dir1/link") != -1);
363 ATF_REQUIRE(!kyua_error_is_set(kyua_fs_cleanup("root")));
364 ATF_REQUIRE(!lookup(".", "root", DT_DIR));
368 ATF_TC(cleanup__mount_point__busy);
369 ATF_TC_HEAD(cleanup__mount_point__busy, tc)
371 atf_tc_set_md_var(tc, "require.user", "root");
373 ATF_TC_BODY(cleanup__mount_point__busy, tc)
375 ATF_REQUIRE(mkdir("root", 0755) != -1);
376 ATF_REQUIRE(mkdir("root/dir1", 0755) != -1);
377 mount_tmpfs("root/dir1");
379 pid_t pid = fork();
380 ATF_REQUIRE(pid != -1);
381 if (pid == 0) {
382 if (chdir("root/dir1") == -1)
383 abort();
385 atf_utils_create_file("dont-delete-me", "%s", "");
386 atf_utils_create_file("../../done", "%s", "");
388 pause();
389 exit(EXIT_SUCCESS);
390 } else {
391 fprintf(stderr, "Waiting for child to finish preparations\n");
392 while (!atf_utils_file_exists("done")) {}
393 fprintf(stderr, "Child done; cleaning up\n");
395 ATF_REQUIRE(kyua_error_is_set(kyua_fs_cleanup("root")));
396 ATF_REQUIRE(atf_utils_file_exists("root/dir1/dont-delete-me"));
398 fprintf(stderr, "Killing child\n");
399 ATF_REQUIRE(kill(pid, SIGKILL) != -1);
400 int status;
401 ATF_REQUIRE(waitpid(pid, &status, 0) != -1);
403 ATF_REQUIRE(!kyua_error_is_set(kyua_fs_cleanup("root")));
404 ATF_REQUIRE(!lookup(".", "root", DT_DIR));
409 ATF_TC_WITHOUT_HEAD(concat__one);
410 ATF_TC_BODY(concat__one, tc)
412 char* path;
413 ATF_REQUIRE(!kyua_error_is_set(kyua_fs_concat(&path, "foo", NULL)));
414 ATF_REQUIRE_STREQ("foo", path);
415 free(path);
419 ATF_TC_WITHOUT_HEAD(concat__two);
420 ATF_TC_BODY(concat__two, tc)
422 char* path;
423 ATF_REQUIRE(!kyua_error_is_set(kyua_fs_concat(&path, "foo", "bar", NULL)));
424 ATF_REQUIRE_STREQ("foo/bar", path);
425 free(path);
429 ATF_TC_WITHOUT_HEAD(concat__several);
430 ATF_TC_BODY(concat__several, tc)
432 char* path;
433 ATF_REQUIRE(!kyua_error_is_set(kyua_fs_concat(&path, "/usr", ".", "bin",
434 "ls", NULL)));
435 ATF_REQUIRE_STREQ("/usr/./bin/ls", path);
436 free(path);
440 ATF_TC_WITHOUT_HEAD(current_path__ok);
441 ATF_TC_BODY(current_path__ok, tc)
443 char* previous;
444 ATF_REQUIRE(!kyua_error_is_set(kyua_fs_current_path(&previous)));
446 ATF_REQUIRE(mkdir("root", 0755) != -1);
447 ATF_REQUIRE(chdir("root") != -1);
448 char* cwd;
449 ATF_REQUIRE(!kyua_error_is_set(kyua_fs_current_path(&cwd)));
451 char* exp_cwd;
452 ATF_REQUIRE(!kyua_error_is_set(kyua_fs_concat(&exp_cwd, previous, "root",
453 NULL)));
454 ATF_REQUIRE_STREQ(exp_cwd, cwd);
456 free(exp_cwd);
457 free(cwd);
458 free(previous);
462 ATF_TC_WITHOUT_HEAD(current_path__enoent);
463 ATF_TC_BODY(current_path__enoent, tc)
465 char* previous;
466 ATF_REQUIRE(!kyua_error_is_set(kyua_fs_current_path(&previous)));
468 ATF_REQUIRE(mkdir("root", 0755) != -1);
469 ATF_REQUIRE(chdir("root") != -1);
470 ATF_REQUIRE(rmdir("../root") != -1);
471 char* cwd = (char*)0xdeadbeef;
472 kyua_error_t error = kyua_fs_current_path(&cwd);
473 ATF_REQUIRE(kyua_error_is_set(error));
474 ATF_REQUIRE(kyua_error_is_type(error, "libc"));
475 ATF_REQUIRE_EQ(ENOENT, kyua_libc_error_errno(error));
476 ATF_REQUIRE_EQ((char*)0xdeadbeef, cwd);
477 kyua_error_free(error);
479 free(previous);
483 ATF_TC_WITHOUT_HEAD(make_absolute__absolute);
484 ATF_TC_BODY(make_absolute__absolute, tc)
486 char* absolute;
487 ATF_REQUIRE(!kyua_error_is_set(kyua_fs_make_absolute(
488 "/this/is/absolute", &absolute)));
489 ATF_REQUIRE_STREQ("/this/is/absolute", absolute);
490 free(absolute);
494 ATF_TC_WITHOUT_HEAD(make_absolute__relative);
495 ATF_TC_BODY(make_absolute__relative, tc)
497 kyua_error_t error;
498 char* absolute;
500 DIR* previous = opendir(".");
501 ATF_REQUIRE(previous != NULL);
502 ATF_REQUIRE(chdir("/usr") != -1);
503 error = kyua_fs_make_absolute("bin/foobar", &absolute);
504 const int previous_fd = dirfd(previous);
505 ATF_REQUIRE(fchdir(previous_fd) != -1);
506 close(previous_fd);
508 ATF_REQUIRE(!kyua_error_is_set(error));
509 ATF_REQUIRE_STREQ("/usr/bin/foobar", absolute);
510 free(absolute);
514 ATF_TC(unmount__ok);
515 ATF_TC_HEAD(unmount__ok, tc)
517 atf_tc_set_md_var(tc, "require.user", "root");
519 ATF_TC_BODY(unmount__ok, tc)
521 ATF_REQUIRE(mkdir("mount_point", 0755) != -1);
523 atf_utils_create_file("mount_point/test1", "%s", "");
524 mount_tmpfs("mount_point");
525 atf_utils_create_file("mount_point/test2", "%s", "");
527 ATF_REQUIRE(!atf_utils_file_exists("mount_point/test1"));
528 ATF_REQUIRE( atf_utils_file_exists("mount_point/test2"));
529 kyua_fs_unmount("mount_point");
530 ATF_REQUIRE( atf_utils_file_exists("mount_point/test1"));
531 ATF_REQUIRE(!atf_utils_file_exists("mount_point/test2"));
535 ATF_TC(unmount__fail);
536 ATF_TC_HEAD(unmount__fail, tc)
538 atf_tc_set_md_var(tc, "require.user", "root");
540 ATF_TC_BODY(unmount__fail, tc)
542 kyua_error_t error = kyua_fs_unmount("mount_point");
543 ATF_REQUIRE(kyua_error_is_set(error));
544 kyua_error_free(error);
548 ATF_TP_ADD_TCS(tp)
550 ATF_TP_ADD_TC(tp, cleanup__file);
551 ATF_TP_ADD_TC(tp, cleanup__subdir__empty);
552 ATF_TP_ADD_TC(tp, cleanup__subdir__files_and_directories);
553 ATF_TP_ADD_TC(tp, cleanup__subdir__unprotect_regular);
554 ATF_TP_ADD_TC(tp, cleanup__subdir__unprotect_symlink);
555 ATF_TP_ADD_TC(tp, cleanup__subdir__links);
556 ATF_TP_ADD_TC(tp, cleanup__mount_point__simple);
557 ATF_TP_ADD_TC(tp, cleanup__mount_point__overlayed);
558 ATF_TP_ADD_TC(tp, cleanup__mount_point__nested);
559 ATF_TP_ADD_TC(tp, cleanup__mount_point__links);
560 ATF_TP_ADD_TC(tp, cleanup__mount_point__busy);
562 ATF_TP_ADD_TC(tp, concat__one);
563 ATF_TP_ADD_TC(tp, concat__two);
564 ATF_TP_ADD_TC(tp, concat__several);
566 ATF_TP_ADD_TC(tp, current_path__ok);
567 ATF_TP_ADD_TC(tp, current_path__enoent);
569 ATF_TP_ADD_TC(tp, make_absolute__absolute);
570 ATF_TP_ADD_TC(tp, make_absolute__relative);
572 ATF_TP_ADD_TC(tp, unmount__ok);
573 ATF_TP_ADD_TC(tp, unmount__fail);
575 return atf_no_error();