blob: aa56be04b01b6cbaa32df6123770ddfc2bf6e055 [file]
// 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 <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <lib/debugdata/debugdata.h>
#include <lib/fdio/io.h>
#include <lib/zx/channel.h>
#include <lib/zx/job.h>
#include <lib/zx/vmar.h>
#include <lib/zx/vmo.h>
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#include <zircon/status.h>
#include <fbl/string.h>
#include <fbl/unique_fd.h>
#include <fbl/vector.h>
namespace debugdata {
DebugData::DebugData(async_dispatcher_t* dispatcher, fbl::unique_fd root_dir_fd,
VmoHandler vmo_callback)
: dispatcher_(dispatcher),
vmo_callback_(std::move(vmo_callback)),
root_dir_fd_(std::move(root_dir_fd)) {}
void DebugData::Publish(PublishRequestView request, PublishCompleter::Sync&) {
std::string data_sink(request->data_sink.data(), request->data_sink.size());
zx::channel vmo_token = request->vmo_token.TakeChannel();
auto wait = std::make_shared<async::WaitOnce>(vmo_token.get(), ZX_CHANNEL_PEER_CLOSED);
auto iterator = pending_handlers_.emplace(pending_handlers_.begin(), wait, std::move(data_sink),
std::move(request->data));
wait->Begin(dispatcher_, [this, vmo_token = std::move(vmo_token), iterator = std::move(iterator)](
async_dispatcher_t*, async::WaitOnce*, zx_status_t status,
const zx_packet_signal_t*) mutable {
vmo_token.reset();
auto handler = std::move(*iterator);
pending_handlers_.erase(iterator);
vmo_callback_(std::move(std::get<1>(handler)), std::move(std::get<2>(handler)));
});
}
void DebugData::LoadConfig(LoadConfigRequestView request, LoadConfigCompleter::Sync& completer) {
// When loading debug configuration file, we expect an absolute path.
const fidl::StringView& config_name = request->config_name;
if (config_name[0] != '/') {
// TODO(phosek): Use proper logging mechanism.
fprintf(stderr, "debugdata: error: LoadConfig: '%.*s' is not an absolute path\n",
static_cast<int>(config_name.size()), config_name.data());
completer.Close(ZX_ERR_INVALID_ARGS);
return;
}
fbl::unique_fd fd(openat(root_dir_fd_.get(), config_name.data(), O_RDONLY));
if (!fd) {
fprintf(stderr, "debugdata: error: LoadConfig: failed to open '%.*s': %s\n",
static_cast<int>(config_name.size()), config_name.data(), strerror(errno));
completer.Close(ZX_ERR_NOT_FOUND);
return;
}
zx::vmo vmo;
zx_status_t status = fdio_get_vmo_clone(fd.get(), vmo.reset_and_get_address());
if (status != ZX_OK) {
fprintf(stderr, "debugdata: error: LoadConfig: failed to load VMO: %s\n",
zx_status_get_string(status));
completer.Close(status);
return;
}
vmo.set_property(ZX_PROP_NAME, config_name.data(), config_name.size());
completer.Reply(std::move(vmo));
}
void DebugData::DrainData() {
for (auto& handler : pending_handlers_) {
std::get<0>(handler)->Cancel();
vmo_callback_(std::move(std::get<1>(handler)), std::move(std::get<2>(handler)));
}
pending_handlers_.clear();
}
} // namespace debugdata