blob: 6f6ab65b58588e1734763c7c3fdfdcc46f4ea348 [file] [log] [blame]
// 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