diff --git a/userspace/digwatch/digwatch.cpp b/userspace/digwatch/digwatch.cpp index 88f3b7d6..ecfe810d 100644 --- a/userspace/digwatch/digwatch.cpp +++ b/userspace/digwatch/digwatch.cpp @@ -19,7 +19,6 @@ extern "C" { #include #include "rules.h" #include "formats.h" -#include "digwatch.h" #include "utils.h" @@ -35,10 +34,7 @@ static void usage() " -m , --main-lua \n" " Name of lua compiler main file\n" " (default: rules_loader.lua)\n" - " -M Stop collecting after reached.\n" " -N Don't convert port numbers to names.\n" - " -n , --numevents=\n" - " Stop capturing after events\n" " -r , --read=\n" " Read the events from .\n" " --unbuffered Turn off output buffering. This causes every single line\n" @@ -53,42 +49,20 @@ static void usage() // // Event processing loop // -captureinfo do_inspect(sinsp* inspector, - uint64_t cnt, - int duration_to_tot, - digwatch_rules* rules, - digwatch_formats* formats) +void do_inspect(sinsp* inspector, + digwatch_rules* rules, + digwatch_formats* formats) { - captureinfo retval; int32_t res; sinsp_evt* ev; string line; - int duration_start = 0; sinsp_evt_formatter* formatter; // // Loop through the events // - duration_start = ((double)clock()) / CLOCKS_PER_SEC; while(1) { - if(duration_to_tot > 0) - { - int duration_tot = ((double)clock()) / CLOCKS_PER_SEC - duration_start; - if(duration_tot >= duration_to_tot) - { - break; - } - } - if(retval.m_nevts == cnt) - { - // - // End of capture, either because the user stopped it, or because - // we reached the event count specified with -n. - // - break; - } - res = inspector->next(&ev); if(res == SCAP_TIMEOUT) @@ -109,8 +83,6 @@ captureinfo do_inspect(sinsp* inspector, throw sinsp_exception(inspector->getlasterr().c_str()); } - retval.m_nevts++; - if(!inspector->is_debug_enabled() && ev->get_category() & EC_INTERNAL) { @@ -118,13 +90,13 @@ captureinfo do_inspect(sinsp* inspector, } formatter = formats->lookup_formatter(ev->get_check_id()); - if (!formatter) + if(!formatter) { throw sinsp_exception("Error: No formatter for event with id %d " + to_string(ev->get_check_id())); } bool has_all = formatter->tostring(ev, &line); - if (!has_all) { + if(!has_all) { cout << "(missing fields) "; } cout << line; @@ -132,8 +104,6 @@ captureinfo do_inspect(sinsp* inspector, } - - return retval; } // @@ -146,10 +116,7 @@ int digwatch_init(int argc, char **argv) digwatch_rules* rules = NULL; digwatch_formats* formats = NULL; int op; - uint64_t cnt = -1; sinsp_evt::param_fmt event_buffer_format = sinsp_evt::PF_NORMAL; - int duration_to_tot = 0; - captureinfo cinfo; int long_index = 0; string lua_main_filename; string lua_dir = DIGWATCH_INSTALLATION_DIR; @@ -158,7 +125,6 @@ int digwatch_init(int argc, char **argv) static struct option long_options[] = { {"help", no_argument, 0, 'h' }, - {"numevents", required_argument, 0, 'n' }, {"main-lua", required_argument, 0, 'u' }, {"readfile", required_argument, 0, 'r' }, {"unbuffered", no_argument, 0, 0 }, @@ -174,7 +140,7 @@ int digwatch_init(int argc, char **argv) // Parse the args // while((op = getopt_long(argc, argv, - "hm:M:Nn:r:", + "hm:Nr:", long_options, &long_index)) != -1) { switch(op) @@ -186,31 +152,9 @@ int digwatch_init(int argc, char **argv) case 'm': lua_main_filename = optarg; break; - case 'M': - duration_to_tot = atoi(optarg); - if(duration_to_tot <= 0) - { - throw sinsp_exception(string("invalid duration") + optarg); - } - break; case 'N': inspector->set_hostname_and_port_resolution_mode(false); break; - case 'n': - try - { - cnt = sinsp_numparser::parseu64(optarg); - } - catch(...) - { - throw sinsp_exception("can't parse the -n argument, make sure it's a number"); - } - - if(cnt <= 0) - { - throw sinsp_exception(string("invalid event count ") + optarg); - } - break; case '?': result = EXIT_FAILURE; goto exit; @@ -243,7 +187,7 @@ int digwatch_init(int argc, char **argv) #endif } - if (rules_file.size() == 0) { + if(rules_file.size() == 0) { usage(); result = EXIT_FAILURE; goto exit; @@ -252,13 +196,13 @@ int digwatch_init(int argc, char **argv) // char* env_lua_dir = getenv("DIGWATCH_LUA_DIR"); - if (env_lua_dir) + if(env_lua_dir) { lua_dir = string(env_lua_dir); } trim(lua_main_filename); - if (lua_main_filename.size() == 0) + if(lua_main_filename.size() == 0) { lua_main_filename = lua_dir + DIGWATCH_LUA_MAIN; } @@ -274,11 +218,9 @@ int digwatch_init(int argc, char **argv) inspector->set_filter(rules->get_filter()); inspector->open(""); - cinfo = do_inspect(inspector, - cnt, - duration_to_tot, - rules, - formats); + do_inspect(inspector, + rules, + formats); inspector->close(); } diff --git a/userspace/digwatch/digwatch.h b/userspace/digwatch/digwatch.h deleted file mode 100644 index 1281d017..00000000 --- a/userspace/digwatch/digwatch.h +++ /dev/null @@ -1,41 +0,0 @@ -/* -Copyright (C) 2013-2014 Draios inc. - -This file is part of sysdig. - -sysdig is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License version 2 as -published by the Free Software Foundation. - -sysdig is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with sysdig. If not, see . -*/ - -#pragma once - -#ifdef HAS_CAPTURE -#include "../../driver/driver_config.h" -#endif // HAS_CAPTURE - - - -// -// Capture results -// -class captureinfo -{ -public: - captureinfo() - { - m_nevts = 0; - m_time = 0; - } - - uint64_t m_nevts; - uint64_t m_time; -}; diff --git a/userspace/digwatch/lua/compiler.lua b/userspace/digwatch/lua/compiler.lua index b562e269..f804cba3 100644 --- a/userspace/digwatch/lua/compiler.lua +++ b/userspace/digwatch/lua/compiler.lua @@ -338,7 +338,7 @@ end definition uses another macro). --]] -function expand_macros(node, defs, changed) +function expand_macros(ast, defs, changed) function copy(obj) if type(obj) ~= 'table' then return obj end @@ -347,110 +347,127 @@ function expand_macros(node, defs, changed) return res end - if (node.type == "Rule") then - macros = expand_macros(node.filter, defs, changed) - elseif node.type == "Filter" then - if (node.value.type == "Macro") then - if (defs[node.value.value] == nil) then - error("Undefined macro '".. node.value.value .. "' used in filter.") + if (ast.type == "Rule") then + macros = expand_macros(ast.filter, defs, changed) + elseif ast.type == "Filter" then + if (ast.value.type == "Macro") then + if (defs[ast.value.value] == nil) then + error("Undefined macro '".. ast.value.value .. "' used in filter.") end - node.value = copy(defs[node.value.value]) + ast.value = copy(defs[ast.value.value]) changed = true return changed end - return expand_macros(node.value, defs, changed) + return expand_macros(ast.value, defs, changed) - elseif node.type == "BinaryBoolOp" then + elseif ast.type == "BinaryBoolOp" then - if (node.left.type == "Macro") then - if (defs[node.left.value] == nil) then - error("Undefined macro '".. node.left.value .. "' used in filter.") + if (ast.left.type == "Macro") then + if (defs[ast.left.value] == nil) then + error("Undefined macro '".. ast.left.value .. "' used in filter.") end - node.left = copy(defs[node.left.value]) + ast.left = copy(defs[ast.left.value]) changed = true end - if (node.right.type == "Macro") then - if (defs[node.right.value] == nil) then - error("Undefined macro ".. node.right.value .. "used in filter.") + if (ast.right.type == "Macro") then + if (defs[ast.right.value] == nil) then + error("Undefined macro ".. ast.right.value .. "used in filter.") end - node.right = copy(defs[node.right.value]) + ast.right = copy(defs[ast.right.value]) changed = true end - local changed_left = expand_macros(node.left, defs, false) - local changed_right = expand_macros(node.right, defs, false) + local changed_left = expand_macros(ast.left, defs, false) + local changed_right = expand_macros(ast.right, defs, false) return changed or changed_left or changed_right - elseif node.type == "UnaryBoolOp" then - if (node.argument.type == "Macro") then - if (defs[node.argument.value] == nil) then - error("Undefined macro ".. node.argument.value .. "used in filter.") + elseif ast.type == "UnaryBoolOp" then + if (ast.argument.type == "Macro") then + if (defs[ast.argument.value] == nil) then + error("Undefined macro ".. ast.argument.value .. "used in filter.") end - node.argument = copy(defs[node.argument.value]) + ast.argument = copy(defs[ast.argument.value]) changed = true end - return expand_macros(node.argument, defs, changed) + return expand_macros(ast.argument, defs, changed) end return changed end -function get_macros(node, set) - if (node.type == "Macro") then - set[node.value] = true +function get_macros(ast, set) + if (ast.type == "Macro") then + set[ast.value] = true return set end - if node.type == "Filter" then - return get_macros(node.value, set) + if ast.type == "Filter" then + return get_macros(ast.value, set) end - if node.type == "BinaryBoolOp" then - local left = get_macros(node.left, {}) - local right = get_macros(node.right, {}) + if ast.type == "BinaryBoolOp" then + local left = get_macros(ast.left, {}) + local right = get_macros(ast.right, {}) for m, _ in pairs(left) do set[m] = true end for m, _ in pairs(right) do set[m] = true end return set end - if node.type == "UnaryBoolOp" then - return get_macros(node.argument, set) + if ast.type == "UnaryBoolOp" then + return get_macros(ast.argument, set) end return set end -function print_ast(node, level) - local t = node.type +function check_macros(ast) + local macros + if (ast.type == "Rule") then + macros = get_macros(ast.filter, {}) + elseif (ast.type == "MacroDef") then + macros = get_macros(ast.value, {}) + else + error ("Unexpected type: "..t) + end + + for m, _ in pairs(macros) do + if macros[m] == nil then + error ("Undefined macro '"..m.."' used in '"..line.."'") + end + end +end + +function print_ast(ast, level) + local t = ast.type level = level or 0 local prefix = string.rep(" ", level*2) level = level + 1 if t == "Rule" then - print_ast(node.filter, level) - if (node.output) then - print(prefix.."| "..node.output.value) + print_ast(ast.filter, level) + if (ast.output) then + print(prefix.."| "..ast.output.value) end elseif t == "Filter" then - print_ast(node.value, level) + print_ast(ast.value, level) elseif t == "BinaryBoolOp" or t == "BinaryRelOp" then - print(prefix..node.operator) - print_ast(node.left, level) - print_ast(node.right, level) + print(prefix..ast.operator) + print_ast(ast.left, level) + print_ast(ast.right, level) elseif t == "UnaryRelOp" or t == "UnaryBoolOp" then - print (prefix..node.operator) - print_ast(node.argument, level) + print (prefix..ast.operator) + print_ast(ast.argument, level) elseif t == "List" then print(prefix.. "List: ") - for i, v in ipairs(node.elements) do + for i, v in ipairs(ast.elements) do print_ast(v, level) end elseif t == "FieldName" or t == "Number" or t == "String" or t == "BareString" or t == "Macro" then - print (prefix..t.." "..node.value) + print (prefix..t.." "..ast.value) elseif t == "MacroDef" then -- don't print for now @@ -491,20 +508,8 @@ function compiler.compile_line(line, macro_defs) return {} end - local macros - if (ast.type == "Rule") then - macros = get_macros(ast.filter, {}) - elseif (ast.type == "MacroDef") then - macros = get_macros(ast.value, {}) - else - error ("Unexpected type: "..t) - end - - for m, _ in pairs(macros) do - if macros[m] == nil then - error ("Undefined macro '"..m.."' used in '"..line.."'") - end - end + -- check that any macros used have already been defined + check_macros(ast) if (ast.type == "MacroDef") then -- Parsed line is a macro definition, so update our dictionary of macros and diff --git a/userspace/digwatch/lua/rule_loader.lua b/userspace/digwatch/lua/rule_loader.lua index ec0a1aac..ec4f3583 100644 --- a/userspace/digwatch/lua/rule_loader.lua +++ b/userspace/digwatch/lua/rule_loader.lua @@ -7,15 +7,18 @@ local compiler = require "compiler" -local function mark_check_nodes(ast, index) +--[[ + Traverse AST, adding the passed-in 'index' to each node that contains a relational expression +--]] +local function mark_relational_nodes(ast, index) local t = ast.type if t == "BinaryBoolOp" then - mark_check_nodes(ast.left, index) - mark_check_nodes(ast.right, index) + mark_relational_nodes(ast.left, index) + mark_relational_nodes(ast.right, index) elseif t == "UnaryBoolOp" then - mark_check_nodes(ast.argument, index) + mark_relational_nodes(ast.argument, index) elseif t == "BinaryRelOp" then ast.index = index @@ -95,11 +98,20 @@ function load_rule(r) error ("Unexpected type in load_rule: "..line_ast.type) end + -- Register a formatter with the output string from this rule digwatch.set_formatter(state.n_rules, line_ast.output.value) - mark_check_nodes(line_ast.filter.value, state.n_rules) + + -- Store the index of this formatter in each relational expression that + -- this rule contains. + -- This index will eventually be stamped in events passing this rule, and + -- we'll use it later to determine which output to display when we get an + -- event. + mark_relational_nodes(line_ast.filter.value, state.n_rules) state.n_rules = state.n_rules + 1 + -- Rule ASTs are merged together into one big AST, with "OR" between each + -- rule. if (state.filter_ast == nil) then state.filter_ast = line_ast.filter.value else diff --git a/userspace/digwatch/lua/parser-smoke.sh b/userspace/digwatch/lua/smoke.sh similarity index 92% rename from userspace/digwatch/lua/parser-smoke.sh rename to userspace/digwatch/lua/smoke.sh index ae8e762b..216b8097 100755 --- a/userspace/digwatch/lua/parser-smoke.sh +++ b/userspace/digwatch/lua/smoke.sh @@ -2,13 +2,13 @@ function error_exit_good { - echo "Error: '$1' did not parse" 1>&2 + echo "Error: '$1' did not compiler" 1>&2 exit 1 } function error_exit_bad { - echo "Error: incorrect filter '$1' parsed ok" 1>&2 + echo "Error: incorrect filter '$1' compiler ok" 1>&2 exit 1 } @@ -72,6 +72,7 @@ good "a : evt.dir=>" good "inbound: (syscall.type=listen and evt.dir='>') or (syscall.type=accept and evt.dir='<')" bad "a:" bad "a : b | bla" +bad "b and d" echo