1 // Copyright 2017 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <dirent.h>
6 #include <errno.h>
7 #include <fcntl.h>
8 #include <stdlib.h>
9 #include <stdio.h>
10 #include <string.h>
11 #include <sys/stat.h>
12 #include <unistd.h>
13 
14 #include <launchpad/launchpad.h>
15 #include <lib/fdio/namespace.h>
16 #include <zircon/compiler.h>
17 #include <zircon/syscalls.h>
18 #include <unittest/unittest.h>
19 
20 typedef struct {
21     const char* local;
22     const char* remote;
23 } nstab_t;
24 
25 static nstab_t NS[] = {
26     { "/bin", "/boot/bin" },
27     { "/lib", "/boot/lib" },
28     { "/fake/dev", "/tmp/fake-namespace-test/dev" },
29     { "/fake/tmp", "/tmp/fake-namespace-test-tmp" },
30 };
31 
namespace_create_test(void)32 static bool namespace_create_test(void) {
33     BEGIN_TEST;
34 
35     ASSERT_TRUE(mkdir("/tmp/fake-namespace-test", 066) == 0 || errno == EEXIST, "");
36     ASSERT_TRUE(mkdir("/tmp/fake-namespace-test/dev", 066) == 0 || errno == EEXIST, "");
37     ASSERT_TRUE(mkdir("/tmp/fake-namespace-test-tmp", 066) == 0 || errno == EEXIST, "");
38 
39     // Create new ns
40     fdio_ns_t* ns;
41     ASSERT_EQ(fdio_ns_create(&ns), ZX_OK, "");
42     for (unsigned n = 0; n < countof(NS); n++) {
43         int fd = open(NS[n].remote, O_RDONLY | O_DIRECTORY);
44         ASSERT_GT(fd, 0, "");
45         ASSERT_EQ(fdio_ns_bind_fd(ns, NS[n].local, fd), ZX_OK, "");
46         ASSERT_EQ(close(fd), 0, "");
47     }
48     ASSERT_EQ(fdio_ns_chdir(ns), ZX_OK, "");
49 
50     DIR* dir;
51     struct dirent* de;
52 
53     // should show "bin", "lib", "fake" -- our rootdir
54     ASSERT_NONNULL((dir = opendir(".")), "");
55     ASSERT_NONNULL((de = readdir(dir)), "");
56     ASSERT_EQ(strcmp(de->d_name, "."), 0, "");
57     ASSERT_NONNULL((de = readdir(dir)), "");
58     ASSERT_EQ(strcmp(de->d_name, "fake"), 0, "");
59     ASSERT_NONNULL((de = readdir(dir)), "");
60     ASSERT_EQ(strcmp(de->d_name, "lib"), 0, "");
61     ASSERT_NONNULL((de = readdir(dir)), "");
62     ASSERT_EQ(strcmp(de->d_name, "bin"), 0, "");
63     ASSERT_EQ(closedir(dir), 0, "");
64 
65     // should show "fake" directory, containing parent's pre-allocated tmp dir.
66     ASSERT_NONNULL((dir = opendir("fake")), "");
67     ASSERT_NONNULL((de = readdir(dir)), "");
68     ASSERT_EQ(strcmp(de->d_name, "."), 0, "");
69     ASSERT_NONNULL((de = readdir(dir)), "");
70     ASSERT_EQ(strcmp(de->d_name, "tmp"), 0, "");
71     ASSERT_NONNULL((de = readdir(dir)), "");
72     ASSERT_EQ(strcmp(de->d_name, "dev"), 0, "");
73     ASSERT_EQ(closedir(dir), 0, "");
74 
75     // Try doing some basic file ops within the namespace
76     int fd = open("fake/tmp/newfile", O_CREAT | O_RDWR | O_EXCL);
77     ASSERT_GT(fd, 0, "");
78     ASSERT_GT(write(fd, "hello", strlen("hello")), 0, "");
79     ASSERT_EQ(close(fd), 0, "");
80     ASSERT_EQ(unlink("fake/tmp/newfile"), 0, "");
81     ASSERT_EQ(mkdir("fake/tmp/newdir", 0666), 0, "");
82     ASSERT_EQ(rename("fake/tmp/newdir", "fake/tmp/olddir"), 0, "");
83     ASSERT_EQ(rmdir("fake/tmp/olddir"), 0, "");
84 
85     END_TEST;
86 }
87 
88 BEGIN_TEST_CASE(namespace_tests)
RUN_TEST_MEDIUM(namespace_create_test)89 RUN_TEST_MEDIUM(namespace_create_test)
90 END_TEST_CASE(namespace_tests)
91 
92 int main(int argc, char** argv) {
93     return unittest_run_all_tests(argc, argv) ? 0 : -1;
94 }
95