1 // Copyright 2012 Google Inc.
2 // All rights reserved.
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
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.
50 static void run_mount_tmpfs(const char*) KYUA_DEFS_NORETURN
;
53 /// Operating systems recognized by the code below.
63 /// The current operating system.
64 static enum os_type current_os
=
65 #if defined(__FreeBSD__)
67 #elif defined(__linux__)
69 #elif defined(__NetBSD__)
71 #elif defined(__SunOS__)
79 /// Checks if a directory entry exists and matches a specific type.
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).
85 /// \return True if the entry exists and matches the given type; false
88 lookup(const char* dir
, const char* name
, const int expected_type
)
90 DIR* dirp
= opendir(dir
);
91 ATF_REQUIRE(dirp
!= NULL
);
95 while (!found
&& (dp
= readdir(dirp
)) != NULL
) {
96 if (strcmp(dp
->d_name
, name
) == 0 &&
97 dp
->d_type
== expected_type
) {
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.
112 run_mount_tmpfs(const char* mount_point
)
114 const char* mount_args
[16];
117 switch (current_os
) {
119 mount_args
[last
++] = "mdmfs";
120 mount_args
[last
++] = "-s16m";
121 mount_args
[last
++] = "md";
122 mount_args
[last
++] = mount_point
;
126 mount_args
[last
++] = "mount";
127 mount_args
[last
++] = "-ttmpfs";
128 mount_args
[last
++] = "tmpfs";
129 mount_args
[last
++] = mount_point
;
133 mount_args
[last
++] = "mount";
134 mount_args
[last
++] = "-ttmpfs";
135 mount_args
[last
++] = "tmpfs";
136 mount_args
[last
++] = mount_point
;
140 mount_args
[last
++] = "mount";
141 mount_args
[last
++] = "-Ftmpfs";
142 mount_args
[last
++] = "tmpfs";
143 mount_args
[last
++] = mount_point
;
147 err(123, "Don't know how to mount a file system for testing "
150 mount_args
[last
] = NULL
;
153 printf("Mounting tmpfs onto %s with:", mount_point
);
154 for (arg
= &mount_args
[0]; *arg
!= NULL
; arg
++)
158 const int ret
= execvp(mount_args
[0], KYUA_DEFS_UNCONST(mount_args
));
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.
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();
182 ATF_REQUIRE(pid
!= -1);
184 run_mount_tmpfs(mount_point
);
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 "
192 ATF_REQUIRE_EQ(EXIT_SUCCESS
, WEXITSTATUS(status
));
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
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
)) {
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");
380 ATF_REQUIRE(pid
!= -1);
382 if (chdir("root/dir1") == -1)
385 atf_utils_create_file("dont-delete-me", "%s", "");
386 atf_utils_create_file("../../done", "%s", "");
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);
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
)
413 ATF_REQUIRE(!kyua_error_is_set(kyua_fs_concat(&path
, "foo", NULL
)));
414 ATF_REQUIRE_STREQ("foo", path
);
419 ATF_TC_WITHOUT_HEAD(concat__two
);
420 ATF_TC_BODY(concat__two
, tc
)
423 ATF_REQUIRE(!kyua_error_is_set(kyua_fs_concat(&path
, "foo", "bar", NULL
)));
424 ATF_REQUIRE_STREQ("foo/bar", path
);
429 ATF_TC_WITHOUT_HEAD(concat__several
);
430 ATF_TC_BODY(concat__several
, tc
)
433 ATF_REQUIRE(!kyua_error_is_set(kyua_fs_concat(&path
, "/usr", ".", "bin",
435 ATF_REQUIRE_STREQ("/usr/./bin/ls", path
);
440 ATF_TC_WITHOUT_HEAD(current_path__ok
);
441 ATF_TC_BODY(current_path__ok
, tc
)
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);
449 ATF_REQUIRE(!kyua_error_is_set(kyua_fs_current_path(&cwd
)));
452 ATF_REQUIRE(!kyua_error_is_set(kyua_fs_concat(&exp_cwd
, previous
, "root",
454 ATF_REQUIRE_STREQ(exp_cwd
, cwd
);
462 ATF_TC_WITHOUT_HEAD(current_path__enoent
);
463 ATF_TC_BODY(current_path__enoent
, tc
)
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
);
483 ATF_TC_WITHOUT_HEAD(make_absolute__absolute
);
484 ATF_TC_BODY(make_absolute__absolute
, tc
)
487 ATF_REQUIRE(!kyua_error_is_set(kyua_fs_make_absolute(
488 "/this/is/absolute", &absolute
)));
489 ATF_REQUIRE_STREQ("/this/is/absolute", absolute
);
494 ATF_TC_WITHOUT_HEAD(make_absolute__relative
);
495 ATF_TC_BODY(make_absolute__relative
, tc
)
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);
508 ATF_REQUIRE(!kyua_error_is_set(error
));
509 ATF_REQUIRE_STREQ("/usr/bin/foobar", absolute
);
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
);
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();