blob: 0661a587cfbc46b280ac938e1ed1eef67a5998f3 [file] [log] [blame]
// Copyright 2019 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 "src/developer/exception_broker/limbo_client/options.h"
#include <zircon/exception.h>
#include <zircon/status.h>
#include "src/developer/exception_broker/limbo_client/limbo_client.h"
#include "src/lib/fxl/strings/string_printf.h"
namespace fuchsia {
namespace exception {
namespace {
zx_status_t EnableLimbo(LimboClient*, const std::vector<const char*>&, std::ostream&);
zx_status_t DisableLimbo(LimboClient*, const std::vector<const char*>&, std::ostream&);
zx_status_t ListLimbo(LimboClient*, const std::vector<const char*>&, std::ostream&);
zx_status_t ReleaseFromLimbo(LimboClient*, const std::vector<const char*>&, std::ostream&);
struct Option {
std::string name;
std::string description;
OptionFunction func = nullptr;
};
const Option kOptions[] = {
{"enable", "Enable the process limbo. It will now begin to capture crashing processes.",
EnableLimbo},
{"disable", "Disable the process limbo. Will free any pending processes waiting in it.",
DisableLimbo},
{"list", "Lists the processes currently waiting on limbo. The limbo must be active.",
ListLimbo},
{"release",
"Release a process from limbo. The limbo must be active. Usage: limbo release <pid>.",
ReleaseFromLimbo},
};
void PrintUsage(std::ostream& os) {
os << R"(Usage: limbo [--help] <option>
The process limbo is a service that permits the system to suspend any processes that throws an
exception (crash) for later processing/debugging. This CLI tool permits to query and modify the
state of the limbo.
Options:
--help: Prints this message.
)";
for (const Option& option : kOptions) {
os << " " << option.name << ": " << option.description << std::endl;
}
}
// Actions Implementations -------------------------------------------------------------------------
zx_status_t EnableLimbo(LimboClient* limbo, const std::vector<const char*>& argv,
std::ostream& os) {
if (limbo->active()) {
os << "Limbo is already active." << std::endl;
return ZX_OK;
}
if (zx_status_t status = limbo->SetActive(true); status != ZX_OK) {
os << "Could not activate limbo: " << zx_status_get_string(status) << std::endl;
return status;
}
os << "Activated the process limbo." << std::endl;
return ZX_OK;
}
zx_status_t DisableLimbo(LimboClient* limbo, const std::vector<const char*>& argv,
std::ostream& os) {
if (!limbo->active()) {
os << "Limbo is already deactivated." << std::endl;
return ZX_OK;
}
if (zx_status_t status = limbo->SetActive(false); status != ZX_OK) {
os << "Could not deactivate limbo: " << zx_status_get_string(status) << std::endl;
return status;
}
os << "Deactivated the process limbo. All contained processes have been freed." << std::endl;
return ZX_OK;
}
zx_status_t ListLimbo(LimboClient* client, const std::vector<const char*>& argv, std::ostream& os) {
if (!client->active()) {
os << "Process limbo is not active." << std::endl;
return ZX_OK;
}
std::vector<LimboClient::ProcessDescription> processes;
if (zx_status_t status = client->ListProcesses(&processes); status != ZX_OK) {
os << "Could not list the process limbo: " << zx_status_get_string(status) << std::endl;
return status;
}
if (processes.empty()) {
os << "No processes currently on limbo." << std::endl;
return ZX_OK;
}
os << "Processes currently on limbo: " << std::endl;
for (const auto& process : processes) {
auto msg = fxl::StringPrintf("%s (pid: %lu), thread %s (tid: %lu) on exception: %s",
process.process_name.c_str(), process.process_koid,
process.thread_name.c_str(), process.thread_koid,
zx_exception_get_string(process.exception));
os << "- " << msg << std::endl;
}
return ZX_OK;
}
zx_status_t ReleaseFromLimbo(LimboClient* client, const std::vector<const char*>& argv,
std::ostream& os) {
if (!client->active()) {
os << "Process limbo is not active." << std::endl;
return ZX_OK;
}
if (argv.size() != 3u) {
os << "Release Usage: limbo release <pid>" << std::endl;
return ZX_ERR_INVALID_ARGS;
}
uint64_t pid = std::atoll(argv[2]);
if (pid == 0) {
os << "Invalid pid " << argv[2] << std::endl;
os << "Release Usage: limbo release <pid>" << std::endl;
return ZX_ERR_INVALID_ARGS;
}
if (zx_status_t status = client->Release(pid); status != ZX_OK) {
if (status == ZX_ERR_NOT_FOUND) {
os << "Could not find pid: " << pid << std::endl;
}
return status;
}
os << "Successfully release process " << pid << " from limbo." << std::endl;
return ZX_OK;
}
} // namespace
OptionFunction ParseArgs(int argc, const char* argv[], std::ostream& os) {
if (argc == 1 || std::string(argv[1]) == "--help") {
PrintUsage(os);
return nullptr;
}
for (const Option& option : kOptions) {
if (option.name == argv[1])
return option.func;
}
os << "Could not find option: " << argv[1] << std::endl;
PrintUsage(os);
return nullptr;
}
} // namespace exception
} // namespace fuchsia