blob: d7c142b7a92359e1b80b4e71b80a3e9ca77afad4 [file] [log] [blame]
// Copyright 2018 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 "connect.h"
#include <fuchsia/inspect/cpp/fidl.h>
#include <lib/fdio/util.h>
#include <lib/fxl/files/directory.h>
#include <lib/fxl/files/file.h>
#include <lib/fxl/files/path.h>
#include <lib/fxl/strings/concatenate.h>
#include <lib/fxl/strings/join_strings.h>
#include <lib/fxl/strings/split_string.h>
#include <lib/fxl/strings/substitute.h>
#include <zircon/device/vfs.h>
namespace iquery {
namespace {
std::string InspectServicePath(const std::string& directory) {
return fxl::Concatenate({files::AbsolutePath(directory), "/",
fxl::StringView(fuchsia::inspect::Inspect::Name_)});
}
// Connect to the Inspect interface on a path that may end within the
// inspect hierarchy itself. For example, if the file hub/objects is an
// entry point for inspect, and objects contains a child "child_object",
// this function allows opening "/hub/objects/child_object" by path.
zx_status_t ConnectToPath(const std::string& in_path,
fuchsia::inspect::InspectSyncPtr* out_ptr) {
std::string path = files::AbsolutePath(in_path);
auto pieces = fxl::SplitString(path, "/", fxl::kTrimWhitespace,
fxl::kSplitWantNonEmpty);
fuchsia::inspect::InspectSyncPtr inspect_ptr;
std::string current_path = "/";
for (const auto& piece : pieces) {
if (inspect_ptr.is_bound()) {
// If the request has already been open, recurse by opening children over
// the API.
fuchsia::inspect::InspectSyncPtr next_request;
bool ok;
inspect_ptr->OpenChild({piece.begin(), piece.length()},
next_request.NewRequest(), &ok);
if (!ok) {
return ZX_ERR_NOT_FOUND;
}
inspect_ptr = std::move(next_request);
} else {
// If the request has not been open, recurse by going down a directory
// level. Once an Inspect directory is found, open the request so that
// recursing can continue within the API.
current_path.append({piece.data(), piece.size()});
current_path.append("/");
if (files::IsFile(InspectServicePath(current_path))) {
zx_status_t status = fdio_service_connect(
InspectServicePath(current_path).c_str(),
inspect_ptr.NewRequest().TakeChannel().release());
if (status != ZX_OK) {
return status;
}
}
}
}
if (inspect_ptr.is_bound()) {
if (out_ptr) {
*out_ptr = std::move(inspect_ptr);
}
return ZX_OK;
}
return ZX_ERR_INVALID_ARGS;
} // namespace
} // namespace
Connection::Connection(const std::string& directory_path)
: directory_path_(directory_path) {}
bool Connection::Validate() {
if (files::IsFile(InspectServicePath(directory_path_))) {
return true;
}
return ConnectToPath(directory_path_, nullptr) == ZX_OK;
}
zx_status_t Connection::Connect(
fidl::InterfaceRequest<fuchsia::inspect::Inspect> request) {
if (files::IsFile(InspectServicePath(directory_path_))) {
return fdio_service_connect(InspectServicePath(directory_path_).c_str(),
request.TakeChannel().release());
}
auto parts = fxl::SplitString(directory_path_, "/", fxl::kTrimWhitespace,
fxl::kSplitWantNonEmpty);
if (parts.size() == 0) {
return ZX_ERR_NOT_FOUND;
}
auto last_part = parts.back();
parts.pop_back();
fuchsia::inspect::InspectSyncPtr parent;
zx_status_t status = ConnectToPath(fxl::JoinStrings(parts, "/"), &parent);
if (status != ZX_OK) {
return status;
}
bool ok;
parent->OpenChild({last_part.data(), last_part.size()}, std::move(request),
&ok);
if (ok) {
return ZX_OK;
}
return ZX_ERR_NOT_FOUND;
}
fuchsia::inspect::InspectSyncPtr Connection::SyncOpen() {
fuchsia::inspect::InspectSyncPtr ret;
zx_status_t status = Connect(ret.NewRequest());
if (status != ZX_OK) {
FXL_VLOG(1) << "Failed to connect: " << status;
ret.Unbind();
}
return ret;
}
fuchsia::inspect::InspectPtr Connection::Open() {
fuchsia::inspect::InspectPtr ret;
zx_status_t status = Connect(ret.NewRequest());
if (status != ZX_OK) {
FXL_VLOG(1) << "Failed to connect: " << status;
ret.Unbind();
}
return ret;
}
} // namespace iquery