osquery-1/osquery/devtools/printer.cpp
Alexander dcfe83a0aa
Helper functions tryTake, tryTakeCopy to lookup in key-value tables (#4833)
There are a lot of lookups in the maps the osquery code. Most of them are verbose and not-optimal with check if such key exists in the table before get access. Some of them consists error e.g.:
```c++
    r["uid"] = row.count("uuid") > 0 ? row.at("uid") : "";
```
Introduced code will help to avoid the most of such problems.
2018-08-28 12:31:10 +01:00

161 lines
4.5 KiB
C++

/**
* Copyright (c) 2014-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under both the Apache 2.0 license (found in the
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
* in the COPYING file in the root directory of this source tree).
* You may select, at your option, one of the above-listed licenses.
*/
#include <iostream>
#include <sstream>
#include <osquery/core.h>
#include <osquery/flags.h>
#include "osquery/core/conversions.h"
#include "osquery/core/map_take.h"
#include "osquery/core/process.h"
#include "osquery/devtools/devtools.h"
namespace osquery {
DECLARE_string(nullvalue);
static std::vector<char> kOffset = {0, 0};
static std::string kToken = "|";
std::string generateToken(const std::map<std::string, size_t>& lengths,
const std::vector<std::string>& columns) {
std::string out = "+";
for (const auto& col : columns) {
size_t size = tryTakeCopy(lengths, col).takeOr(col.size()) + 2;
if (getEnvVar("ENHANCE").is_initialized()) {
std::string e = "\xF0\x9F\x90\x8C";
e[2] += kOffset[1];
e[3] += kOffset[0];
for (size_t i = 0; i < size; i++) {
e[3] = '\x8c' + kOffset[0]++;
if (e[3] == '\xbf') {
e[3] = '\x80';
kOffset[1] = (kOffset[1] > 3 && kOffset[1] < 8) ? 9 : kOffset[1];
e[2] = '\x90' + ++kOffset[1];
kOffset[0] = 0;
}
if (kOffset[1] == ('\x97' - '\x8d')) {
kOffset = {0, 0};
}
out += e.c_str();
}
} else {
out += std::string(size, '-');
}
out += "+";
}
out += "\n";
return out;
}
std::string generateHeader(const std::map<std::string, size_t>& lengths,
const std::vector<std::string>& columns) {
if (getEnvVar("ENHANCE").is_initialized()) {
kToken = "\xF0\x9F\x91\x8D";
}
std::string out = kToken;
for (const auto& col : columns) {
out += " " + col;
if (lengths.count(col) > 0) {
int buffer_size = static_cast<int>(lengths.at(col) - utf8StringSize(col));
if (buffer_size > 0) {
out += std::string(buffer_size, ' ');
}
}
out += ' ';
out += kToken;
}
out += "\n";
return out;
}
std::string generateRow(const Row& r,
const std::map<std::string, size_t>& lengths,
const std::vector<std::string>& order) {
std::string out;
for (const auto& column : order) {
size_t size = 0;
// Print a terminator for the previous value or lhs, followed by spaces.
out += kToken + ' ';
if (r.count(column) == 0 || lengths.count(column) == 0) {
size = column.size() - utf8StringSize(FLAGS_nullvalue);
out += FLAGS_nullvalue;
} else {
int buffer_size =
static_cast<int>(lengths.at(column) - utf8StringSize(r.at(column)));
if (buffer_size >= 0) {
size = static_cast<size_t>(buffer_size);
out += r.at(column);
}
}
out += std::string(size + 1, ' ');
}
if (out.size() > 0) {
// Only append if a row was added.
out += kToken + "\n";
}
return out;
}
void prettyPrint(const QueryData& results,
const std::vector<std::string>& columns,
std::map<std::string, size_t>& lengths) {
if (results.size() == 0) {
return;
}
// Call a final compute using the column names as minimum lengths.
computeRowLengths(results.front(), lengths, true);
// Output a nice header wrapping the column names.
auto separator = generateToken(lengths, columns);
auto header = separator + generateHeader(lengths, columns) + separator;
printf("%s", header.c_str());
// Iterate each row and pretty print.
for (const auto& row : results) {
printf("%s", generateRow(row, lengths, columns).c_str());
}
printf("%s", separator.c_str());
}
void jsonPrint(const QueryData& q) {
printf("[\n");
for (size_t i = 0; i < q.size(); ++i) {
std::string row_string;
if (serializeRowJSON(q[i], row_string).ok()) {
printf(" %s", row_string.c_str());
if (i < q.size() - 1) {
printf(",\n");
}
}
}
printf("\n]\n");
}
void computeRowLengths(const Row& r,
std::map<std::string, size_t>& lengths,
bool use_columns) {
for (const auto& col : r) {
size_t current = tryTakeCopy(lengths, col.first).takeOr(std::size_t{0});
size_t size =
(use_columns) ? utf8StringSize(col.first) : utf8StringSize(col.second);
lengths[col.first] = (size > current) ? size : current;
}
}
}