mirror of
https://github.com/valitydev/osquery-1.git
synced 2024-11-07 09:58:54 +00:00
Merge pull request #1910 from theopolis/null
Allow NULL values, stop using -1 as int/double invalid values
This commit is contained in:
commit
03d0d7e835
@ -11,6 +11,7 @@
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
#include <osquery/flags.h>
|
||||
#include <osquery/core.h>
|
||||
|
||||
#include "osquery/core/conversions.h"
|
||||
@ -18,6 +19,8 @@
|
||||
|
||||
namespace osquery {
|
||||
|
||||
SHELL_FLAG(string, nullvalue, "", "Set string for NULL values, default ''");
|
||||
|
||||
static std::vector<size_t> kOffset = {0, 0};
|
||||
static std::string kToken = "|";
|
||||
|
||||
@ -25,27 +28,26 @@ 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) {
|
||||
if (lengths.count(col) > 0) {
|
||||
if (getenv("ENHANCE") != nullptr) {
|
||||
std::string e = "\xF0\x9F\x90\x8C";
|
||||
e[2] += kOffset[1];
|
||||
e[3] += kOffset[0];
|
||||
for (size_t i = 0; i < lengths.at(col) + 2; 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();
|
||||
size_t size = ((lengths.count(col) > 0) ? lengths.at(col) : col.size()) + 2;
|
||||
if (getenv("ENHANCE") != nullptr) {
|
||||
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;
|
||||
}
|
||||
} else {
|
||||
out += std::string(lengths.at(col) + 2, '-');
|
||||
if (kOffset[1] == ('\x97' - '\x8d')) {
|
||||
kOffset = {0, 0};
|
||||
}
|
||||
out += e.c_str();
|
||||
}
|
||||
} else {
|
||||
out += std::string(size, '-');
|
||||
}
|
||||
out += "+";
|
||||
}
|
||||
@ -63,13 +65,12 @@ std::string generateHeader(const std::map<std::string, size_t>& lengths,
|
||||
for (const auto& col : columns) {
|
||||
out += " " + col;
|
||||
if (lengths.count(col) > 0) {
|
||||
int buffer_size = lengths.at(col) - utf8StringSize(col) + 1;
|
||||
int buffer_size = lengths.at(col) - utf8StringSize(col);
|
||||
if (buffer_size > 0) {
|
||||
out += std::string(buffer_size, ' ');
|
||||
} else {
|
||||
out += ' ';
|
||||
}
|
||||
}
|
||||
out += ' ';
|
||||
out += kToken;
|
||||
}
|
||||
out += "\n";
|
||||
@ -81,15 +82,21 @@ std::string generateRow(const Row& r,
|
||||
const std::vector<std::string>& order) {
|
||||
std::string out;
|
||||
for (const auto& column : order) {
|
||||
if (r.count(column) == 0 || lengths.count(column) == 0) {
|
||||
continue;
|
||||
}
|
||||
// Print a terminator for the previous value or lhs, followed by spaces.
|
||||
size_t size = 0;
|
||||
|
||||
int buffer_size = lengths.at(column) - utf8StringSize(r.at(column)) + 1;
|
||||
if (buffer_size > 0) {
|
||||
out += kToken + " " + r.at(column) + std::string(buffer_size, ' ');
|
||||
// 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 = 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) {
|
||||
@ -126,6 +133,7 @@ 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()) {
|
||||
row_string.pop_back();
|
||||
printf(" %s", row_string.c_str());
|
||||
|
@ -43,13 +43,14 @@ SHELL_FLAG(bool, csv, false, "Set output mode to 'csv'");
|
||||
SHELL_FLAG(bool, json, false, "Set output mode to 'json'");
|
||||
SHELL_FLAG(bool, line, false, "Set output mode to 'line'");
|
||||
SHELL_FLAG(bool, list, false, "Set output mode to 'list'");
|
||||
SHELL_FLAG(string, nullvalue, "", "Set string for NULL values, default ''");
|
||||
SHELL_FLAG(string, separator, "|", "Set output field separator, default '|'");
|
||||
SHELL_FLAG(bool, header, true, "Toggle column headers true/false");
|
||||
|
||||
/// Define short-hand shell switches.
|
||||
SHELL_FLAG(bool, L, false, "List all table names");
|
||||
SHELL_FLAG(string, A, "", "Select all from a table");
|
||||
|
||||
DECLARE_string(nullvalue);
|
||||
}
|
||||
|
||||
static char zHelp[] =
|
||||
@ -694,8 +695,10 @@ static int shell_callback(
|
||||
|
||||
osquery::Row r;
|
||||
for (i = 0; i < nArg; ++i) {
|
||||
if (azCol[i] != nullptr && azArg[i] != nullptr) {
|
||||
r[std::string(azCol[i])] = std::string(azArg[i]);
|
||||
if (azCol[i] != nullptr) {
|
||||
r[std::string(azCol[i])] = (azArg[i] == nullptr)
|
||||
? osquery::FLAGS_nullvalue
|
||||
: std::string(azArg[i]);
|
||||
}
|
||||
}
|
||||
osquery::computeRowLengths(r, p->prettyPrint->lengths);
|
||||
|
@ -236,4 +236,40 @@ TEST_F(VirtualTableTests, test_json_extract) {
|
||||
ASSERT_EQ(results.size(), 1U);
|
||||
EXPECT_EQ(results[0]["test"], "1");
|
||||
}
|
||||
|
||||
TEST_F(VirtualTableTests, test_null_values) {
|
||||
auto dbc = SQLiteDBManager::get();
|
||||
|
||||
std::string statement = "SELECT NULL as null_value;";
|
||||
{
|
||||
QueryData results;
|
||||
auto status = queryInternal(statement, results, dbc->db());
|
||||
EXPECT_TRUE(status.ok());
|
||||
EXPECT_EQ(results[0]["null_value"], "");
|
||||
}
|
||||
|
||||
// Try INTEGER.
|
||||
{
|
||||
QueryData results;
|
||||
statement = "SELECT CAST(NULL as INTEGER) as null_value;";
|
||||
queryInternal(statement, results, dbc->db());
|
||||
EXPECT_EQ(results[0]["null_value"], "");
|
||||
}
|
||||
|
||||
// BIGINT.
|
||||
{
|
||||
QueryData results;
|
||||
statement = "SELECT CAST(NULL as BIGINT) as null_value;";
|
||||
queryInternal(statement, results, dbc->db());
|
||||
EXPECT_EQ(results[0]["null_value"], "");
|
||||
}
|
||||
|
||||
// Try DOUBLE.
|
||||
{
|
||||
QueryData results;
|
||||
statement = "SELECT CAST(NULL as DOUBLE) as null_value;";
|
||||
queryInternal(statement, results, dbc->db());
|
||||
EXPECT_EQ(results[0]["null_value"], "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -182,7 +182,11 @@ int xColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int col) {
|
||||
|
||||
// Attempt to cast each xFilter-populated row/column to the SQLite type.
|
||||
const auto &value = pCur->data[pCur->row][column_name];
|
||||
if (type == TEXT_TYPE) {
|
||||
if (pCur->data[pCur->row].count(column_name) == 0) {
|
||||
// Missing content.
|
||||
VLOG(1) << "Error " << column_name << " is empty";
|
||||
sqlite3_result_null(ctx);
|
||||
} else if (type == TEXT_TYPE) {
|
||||
sqlite3_result_text(ctx, value.c_str(), value.size(), SQLITE_STATIC);
|
||||
} else if (type == INTEGER_TYPE) {
|
||||
long afinite;
|
||||
@ -190,17 +194,19 @@ int xColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int col) {
|
||||
afinite > INT_MAX) {
|
||||
VLOG(1) << "Error casting " << column_name << " (" << value
|
||||
<< ") to INTEGER";
|
||||
afinite = -1;
|
||||
sqlite3_result_null(ctx);
|
||||
} else {
|
||||
sqlite3_result_int(ctx, (int)afinite);
|
||||
}
|
||||
sqlite3_result_int(ctx, (int)afinite);
|
||||
} else if (type == BIGINT_TYPE || type == UNSIGNED_BIGINT_TYPE) {
|
||||
long long afinite;
|
||||
if (!safeStrtoll(value, 10, afinite)) {
|
||||
VLOG(1) << "Error casting " << column_name << " (" << value
|
||||
<< ") to BIGINT";
|
||||
afinite = -1;
|
||||
sqlite3_result_null(ctx);
|
||||
} else {
|
||||
sqlite3_result_int64(ctx, afinite);
|
||||
}
|
||||
sqlite3_result_int64(ctx, afinite);
|
||||
} else if (type == DOUBLE_TYPE) {
|
||||
char *end = nullptr;
|
||||
double afinite = strtod(value.c_str(), &end);
|
||||
@ -208,8 +214,10 @@ int xColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int col) {
|
||||
afinite = 0;
|
||||
VLOG(1) << "Error casting " << column_name << " (" << value
|
||||
<< ") to DOUBLE";
|
||||
sqlite3_result_null(ctx);
|
||||
} else {
|
||||
sqlite3_result_double(ctx, afinite);
|
||||
}
|
||||
sqlite3_result_double(ctx, afinite);
|
||||
} else {
|
||||
LOG(ERROR) << "Error unknown column type " << column_name;
|
||||
}
|
||||
|
@ -545,7 +545,7 @@ void genProcessMemoryMap(int pid, QueryData &results) {
|
||||
}
|
||||
}
|
||||
|
||||
QueryData genProcessMemoryMap(QueryContext& context) {
|
||||
QueryData genProcessMemoryMap(QueryContext &context) {
|
||||
QueryData results;
|
||||
|
||||
auto pidlist = getProcList(context);
|
||||
|
Loading…
Reference in New Issue
Block a user