blob: 5bb545758b1fbfbc091dde1be39195dab3028134 [file] [log] [blame] [edit]
// Copyright 2024 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// FIXME: needed because base/files/file.h does a typedef on `struct stat` and
// does not include its definition.
#include "pmt_tool/utils.h"
#include <sys/stat.h>
#include <absl/time/time.h>
#include <base/files/file.h>
#include <base/logging.h>
#include <base/strings/string_number_conversions.h>
#include <brillo/flag_helper.h>
#include <brillo/syslog_logging.h>
#include "base/files/file_path.h"
#include "base/files/file_util.h"
namespace pmt_tool {
bool ParseCommandLineAndInitLogging(int argc,
const char** argv,
Options& opts) {
// Initialize with defaults.
Options new_opts;
DEFINE_double(i, 1, "Seconds to wait between samples");
DEFINE_uint32(n, 0, "Number of samples to take");
DEFINE_uint32(t, 0, "Sample for the specified number of seconds");
DEFINE_string(f, "raw",
"output format: raw - raw binary format; dbg - debug string; "
"csv - decoded as CSV from raw binary");
DEFINE_string(
m, "",
"Optional path to the PMT metadata directory where pmt.xml is located");
auto help_usage = std::string(argv[0]);
help_usage.append(
" [OPTIONS] [-- [FILE]]\n"
"Sample and decode Intel PMT telemetry to stdout.\n"
"By default samples will be gathered continuously every -i seconds.\n"
"If FILE path is provided, all samples are read from it.\n"
"Note that -t and -n flags are mutually exclusive.\n"
"OPTIONS:");
bool result = brillo::FlagHelper::Init(
argc, argv, help_usage, brillo::FlagHelper::InitFuncType::kReturn,
nullptr);
// Setup logging now that command line was parsed and brillo can process
// verbosity flags.
brillo::InitLog(brillo::kLogToStderr);
// Exit early if parsing failed.
if (!result) {
return result;
}
// Validate flags.
if (FLAGS_t > 0 && FLAGS_n) {
LOG(ERROR) << "-t and -n are mutually exclusive";
return false;
}
if (FLAGS_t && FLAGS_t < FLAGS_i) {
LOG(ERROR) << "-t cannot be lower than -i";
return false;
}
auto val = FormatFromString(FLAGS_f);
if (!val.has_value()) {
LOG(ERROR) << "Unknown format: " << FLAGS_f;
return false;
}
auto metadata_path = base::FilePath(FLAGS_m);
if (!FLAGS_m.empty() && !base::PathExists(metadata_path)) {
LOG(ERROR) << "Metadata directory " << FLAGS_m << " not found";
return false;
}
// Flags are valid, set them.
new_opts.sampling.interval_us =
absl::ToInt64Microseconds(absl::Seconds(FLAGS_i));
new_opts.sampling.duration_seconds = std::ceil(FLAGS_t / FLAGS_i) * FLAGS_i;
if (FLAGS_t != 0) {
new_opts.sampling.duration_samples =
1 + new_opts.sampling.duration_seconds / FLAGS_i;
} else {
new_opts.sampling.duration_samples = FLAGS_n;
}
new_opts.decoding.format = *val;
new_opts.decoding.metadata_path = metadata_path;
// Out of the rest of arguments treat the fist one as a path to the pmt.log.
auto cl = base::CommandLine::ForCurrentProcess();
if (!cl->GetArgs().empty()) {
if (cl->GetArgs().size() > 1) {
LOG(ERROR) << "Only a single input file is supported.";
return false;
}
new_opts.sampling.input_file = base::FilePath(cl->GetArgs()[0]);
base::stat_wrapper_t stat;
errno = 0;
if (base::File::Stat(new_opts.sampling.input_file, &stat)) {
LOG(ERROR) << "Failed to open input file: " << strerror(errno);
return false;
}
}
// Values are good so set the output variable.
opts = new_opts;
return true;
}
} // namespace pmt_tool