| // Copyright 2017 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "garnet/bin/appmgr/namespace_builder.h" |
| |
| #include <lib/fdio/limits.h> |
| #include <lib/fdio/util.h> |
| #include <zircon/processargs.h> |
| |
| #include <fcntl.h> |
| #include <stdlib.h> |
| #include <unistd.h> |
| |
| #include "lib/fsl/io/fd.h" |
| #include "lib/fxl/files/unique_fd.h" |
| |
| namespace component { |
| |
| NamespaceBuilder::NamespaceBuilder() = default; |
| |
| NamespaceBuilder::~NamespaceBuilder() = default; |
| |
| void NamespaceBuilder::AddFlatNamespace(fuchsia::sys::FlatNamespacePtr ns) { |
| if (ns && ns->paths.size() == ns->directories.size()) { |
| for (size_t i = 0; i < ns->paths.size(); ++i) { |
| AddDirectoryIfNotPresent(ns->paths.at(i), |
| std::move(ns->directories.at(i))); |
| } |
| } |
| } |
| |
| void NamespaceBuilder::AddPackage(zx::channel package) { |
| PushDirectoryFromChannel("/pkg", std::move(package)); |
| } |
| |
| void NamespaceBuilder::AddDirectoryIfNotPresent(const std::string& path, |
| zx::channel directory) { |
| if (std::find(paths_.begin(), paths_.end(), path) != paths_.end()) |
| return; |
| PushDirectoryFromChannel(path, std::move(directory)); |
| } |
| |
| void NamespaceBuilder::AddServices(zx::channel services) { |
| PushDirectoryFromChannel("/svc", std::move(services)); |
| } |
| |
| void NamespaceBuilder::AddSandbox( |
| const SandboxMetadata& sandbox, |
| const HubDirectoryFactory& hub_directory_factory) { |
| for (const auto& path : sandbox.dev()) { |
| if (path == "class") { |
| FXL_LOG(WARNING) << "Ignoring request for all device classes"; |
| continue; |
| } |
| PushDirectoryFromPath("/dev/" + path); |
| } |
| |
| for (const auto& path : sandbox.system()) |
| PushDirectoryFromPath("/system/" + path); |
| |
| for (const auto& path : sandbox.pkgfs()) |
| PushDirectoryFromPath("/pkgfs/" + path); |
| |
| for (const auto& feature : sandbox.features()) { |
| if (feature == "persistent-storage") { |
| // TODO(flowerhack): Make this feature more fine-grained. |
| PushDirectoryFromPath("/data"); |
| } else if (feature == "build-info") { |
| PushDirectoryFromPathAs("/pkgfs/packages/build-info/0/data", |
| "/config/build-info"); |
| } else if (feature == "root-ssl-certificates" || feature == "shell") { |
| // "shell" implies "root-ssl-certificates" |
| PushDirectoryFromPathAs("/pkgfs/packages/root_ssl_certificates/0/data", |
| "/config/ssl"); |
| |
| if (feature == "shell") { |
| // TODO(abarth): These permissions should depend on the envionment |
| // in some way so that a shell running at a user-level scope doesn't |
| // have access to all the device drivers and such. |
| PushDirectoryFromPathAs("/pkgfs/packages/shell-commands/0/bin", "/bin"); |
| PushDirectoryFromPath("/blob"); |
| PushDirectoryFromPath("/boot"); |
| PushDirectoryFromPath("/data"); |
| PushDirectoryFromPath("/dev"); |
| PushDirectoryFromChannel("/hub", hub_directory_factory()); |
| PushDirectoryFromPath("/install"); |
| PushDirectoryFromPath("/pkgfs"); |
| PushDirectoryFromPath("/system"); |
| PushDirectoryFromPath("/tmp"); |
| PushDirectoryFromPath("/volume"); |
| } |
| } else if (feature == "shell-commands") { |
| PushDirectoryFromPathAs("/pkgfs/packages/shell-commands/0/bin", "/bin"); |
| } else if (feature == "system-temp") { |
| PushDirectoryFromPath("/tmp"); |
| } else if (feature == "vulkan") { |
| PushDirectoryFromPath("/dev/class/gpu"); |
| PushDirectoryFromPathAs("/system/data/vulkan/icd.d", |
| "/config/vulkan/icd.d"); |
| } |
| } |
| |
| for (const auto& path : sandbox.boot()) |
| PushDirectoryFromPath("/boot/" + path); |
| } |
| |
| void NamespaceBuilder::PushDirectoryFromPath(std::string path) { |
| PushDirectoryFromPathAs(path, path); |
| } |
| |
| void NamespaceBuilder::PushDirectoryFromPathAs(std::string src_path, |
| std::string dst_path) { |
| if (std::find(paths_.begin(), paths_.end(), dst_path) != paths_.end()) |
| return; |
| fxl::UniqueFD dir(open(src_path.c_str(), O_DIRECTORY | O_RDONLY)); |
| if (!dir.is_valid()) |
| return; |
| zx::channel handle = fsl::CloneChannelFromFileDescriptor(dir.get()); |
| if (!handle) { |
| FXL_DLOG(WARNING) << "Failed to clone channel for " << src_path; |
| return; |
| } |
| PushDirectoryFromChannel(std::move(dst_path), std::move(handle)); |
| } |
| |
| void NamespaceBuilder::PushDirectoryFromPathIfNotPresent(std::string path) { |
| if (std::find(paths_.begin(), paths_.end(), path) != paths_.end()) |
| return; |
| PushDirectoryFromPathAs(path, path); |
| } |
| |
| void NamespaceBuilder::PushDirectoryFromChannel(std::string path, |
| zx::channel channel) { |
| FXL_DCHECK(std::find(paths_.begin(), paths_.end(), path) == paths_.end()); |
| types_.push_back(PA_HND(PA_NS_DIR, types_.size())); |
| handles_.push_back(channel.get()); |
| paths_.push_back(std::move(path)); |
| |
| handle_pool_.push_back(std::move(channel)); |
| } |
| |
| fdio_flat_namespace_t* NamespaceBuilder::Build() { |
| path_data_.resize(paths_.size()); |
| for (size_t i = 0; i < paths_.size(); ++i) |
| path_data_[i] = paths_[i].c_str(); |
| |
| flat_ns_.count = types_.size(); |
| flat_ns_.handle = handles_.data(); |
| flat_ns_.type = types_.data(); |
| flat_ns_.path = path_data_.data(); |
| Release(); |
| return &flat_ns_; |
| } |
| |
| fuchsia::sys::FlatNamespace NamespaceBuilder::BuildForRunner() { |
| fuchsia::sys::FlatNamespace flat_namespace; |
| flat_namespace.paths.clear(); |
| flat_namespace.directories.clear(); |
| |
| for (auto& path : paths_) { |
| flat_namespace.paths.push_back(std::move(path)); |
| } |
| |
| for (auto& handle : handle_pool_) { |
| flat_namespace.directories.push_back(std::move(handle)); |
| } |
| return flat_namespace; |
| } |
| |
| void NamespaceBuilder::Release() { |
| for (auto& handle : handle_pool_) |
| (void)handle.release(); |
| handle_pool_.clear(); |
| } |
| |
| } // namespace component |