1 // Copyright 2016 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 #pragma once
6 
7 #include <lib/async-loop/cpp/loop.h>
8 #include <lib/async/cpp/wait.h>
9 #include <lib/fdio/io.h>
10 #include <lib/fdio/vfs.h>
11 #include <lib/memfs/cpp/vnode.h>
12 #include <lib/zx/channel.h>
13 #include <lib/zx/event.h>
14 #include <lib/zx/job.h>
15 #include <zircon/compiler.h>
16 #include <zircon/thread_annotations.h>
17 #include <zircon/types.h>
18 
19 #include "../shared/env.h"
20 #include "../shared/fdio.h"
21 
22 namespace devmgr {
23 
24 // FshostConnections represents the link from fshost to external
25 // sources outside fshost, such as the devmgr.
26 class FshostConnections {
27 public:
28     FshostConnections(zx::channel devfs_root, zx::channel svc_root, zx::channel fs_root,
29                       zx::event event);
30 
31     // Synchronously opens a connection on the requested path.
32     //
33     // TODO: Return an error code, instead of "invalid handle", on error.
34     zx::channel Open(const char* path) const;
35 
36     // Create and install the namespace for the current process, using
37     // the owned channels as connections.
38     zx_status_t CreateNamespace();
39 
Event()40     const zx::event& Event() const {
41         return event_;
42     }
43 
44 private:
45     zx::channel devfs_root_;
46     zx::channel svc_root_;
47     zx::channel fs_root_;
48     zx::event event_;
49 };
50 
51 // FsManager owns multiple sub-filesystems, managing them within a top-level
52 // in-memory filesystem.
53 class FsManager {
54 public:
55     FsManager();
56 
GetConnections()57     const FshostConnections& GetConnections() const {
58         return *connections_.get();
59     }
60 
61     // Created a named VmoFile in "/system". Ownership of |vmo| assumed global.
62     zx_status_t SystemfsAddFile(const char* path, zx_handle_t vmo, zx_off_t off, size_t len);
63 
64     // Signal that "/system" has been mounted.
FuchsiaStart()65     void FuchsiaStart() const {
66         connections_->Event().signal(0, FSHOST_SIGNAL_READY);
67     }
68 
69     // Create "/system", and mount it within the global root.
70     zx_status_t MountSystem();
71 
72     // Identifies if "/system" has already been mounted.
IsSystemMounted()73     bool IsSystemMounted() const {
74         return systemfs_root_ != nullptr;
75     }
76 
77     // Set the "/system" VFS filesystem to become readonly.
78     void SystemfsSetReadonly(bool value);
79 
80     // Pins a handle to a remote filesystem on one of the paths specified
81     // by |kMountPoints|.
82     zx_status_t InstallFs(const char* path, zx::channel h);
83 
84     // Initialize connections to external service managers, and begin
85     // monitoring |event| for a termination event.
86     zx_status_t InitializeConnections(zx::channel root, zx::channel devfs_root,
87                                       zx::channel svc_root, zx::event event);
88 
89 private:
90     // Triggers unmount when the FSHOST_SIGNAL_EXIT signal is raised on an
91     // event contained within |connections_|.
92     //
93     // Sets FSHOST_SIGNAL_EXIT_DONE when unmounting is complete.
94     void WatchExit();
95 
96     // Give a channel to a root directory, where it will begin serving requests.
97     zx_status_t ConnectRoot(zx::channel server);
98 
99     // Create a new channel, and connect to the root directory.
100     // Invokes |ConnectRoot| internally.
101     zx_status_t ServeRoot(zx::channel* out);
102 
103     zx_status_t ServeVnode(fbl::RefPtr<memfs::VnodeDir>& vn, zx::channel server);
104     zx_status_t LocalMount(memfs::VnodeDir* parent, const char* name,
105                            fbl::RefPtr<memfs::VnodeDir>& subtree);
106 
107     static constexpr const char* kMountPoints[] = {
108         "/bin", "/data", "/volume", "/system", "/install", "/blob", "/pkgfs"
109     };
110     fbl::RefPtr<fs::Vnode> mount_nodes[fbl::count_of(kMountPoints)];
111 
112     // The Root VFS manages the following filesystems:
113     // - The global root filesystem (including the mount points)
114     // - "/tmp"
115     memfs::Vfs root_vfs_;
116 
117     // The System VFS manages exclusively the system filesystem.
118     memfs::Vfs system_vfs_;
119     fbl::unique_ptr<async::Loop> global_loop_;
120     async::Wait global_shutdown_;
121 
122     // The base, root directory which serves the rest of the fshost.
123     fbl::RefPtr<memfs::VnodeDir> global_root_;
124     // The globally accessible "/tmp", in-memory filesystem directory.
125     fbl::RefPtr<memfs::VnodeDir> memfs_root_;
126 
127     // The location of an optional system image filesystem.
128     fbl::RefPtr<memfs::VnodeDir> systemfs_root_;
129 
130     // Allows access and signals to external resources.
131     fbl::unique_ptr<FshostConnections> connections_;
132 };
133 
134 // Function which mounts a handle on behalf of the block watcher.
135 void block_device_watcher(fbl::unique_ptr<FsManager> fshost, zx::unowned_job job, bool netboot);
136 
137 } // namespace devmgr
138