diff --git a/lua/compiler.lua b/lua/compiler.lua index b3cdf442..1923a347 100644 --- a/lua/compiler.lua +++ b/lua/compiler.lua @@ -453,17 +453,17 @@ end to the line-oriented compiler. --]] function compiler.init() - return {macros={}} + return {macros={}, ast=nil} end --[[ - Compiles a digwatch filter or macro + Compiles a single line from a digwatch ruleset and updates the passed-in state object. Returns the AST of the line. --]] function compiler.compile_line(line, state) local ast, error_msg = compiler.parser.parse_line(line) if (error_msg) then - return nil, error_msg + error(error_msg) end local macros = get_macros(ast.value, {}) @@ -474,20 +474,31 @@ function compiler.compile_line(line, state) end if (ast.type == "MacroDef") then + -- Parsed line is a macro definition, so update our dictionary of macros and + -- return state.macros[ast.name] = ast.value - return ast, error_msg + return ast + elseif (ast.type == "Filter") then + -- Line is a filter, so expand in-clauses and macro references, then + -- stitch it into global ast + expand_in(ast) repeat expanded = expand_macros(ast, state.macros, false) until expanded == false + if (state.ast == nil) then + state.ast = ast + else + state.ast = { type = "BinaryBoolOp", operator = "or", left = state.ast, right = ast } + end else error("Unexpected top-level AST type: "..ast.type) end - return ast, error_msg + return ast end diff --git a/lua/rule_loader.lua b/lua/rule_loader.lua new file mode 100644 index 00000000..59402c4d --- /dev/null +++ b/lua/rule_loader.lua @@ -0,0 +1,78 @@ +--[[ + Compile and install digwatch rules. + + This module exports functions that are called from digwatch c++-side to compile and install a set of rules. + +--]] + +local compiler = require "compiler" + +local function install_filter(node) + local t = node.type + + if t == "Filter" then + install_filter(node.value) + + elseif t == "BinaryBoolOp" then + filter.nest() --io.write("(") + install_filter(node.left) + filter.bool_op(node.operator) --io.write(" "..node.operator.." ") + install_filter(node.right) + filter.unnest() --io.write(")") + + + elseif t == "UnaryBoolOp" then + filter.nest() --io.write("(") + filter.bool_op(node.operator) -- io.write(" "..node.operator.." ") + install_filter(node.argument) + filter.unnest() -- io.write(")") + + elseif t == "BinaryRelOp" then + filter.rel_expr(node.left.value, node.operator, node.right.value) + -- io.write(node.left.value.." "..node.operator.." "..node.right.value) + + -- xxx still need to handle case where node.right.type=="list" + + elseif t == "UnaryRelOp" then + filter.rel_expr(node.argument.value, node.operator) + --io.write(node.argument.value.." "..node.operator) + + elseif t == "List" then + error("Not handling List yet") + + elseif t == "FieldName" or t == "Number" or t == "String" or t == "BareString" or t == "Macro" then + error ("Unexpected type: "..t) + + io.write(t.." "..node.value) + + elseif t == "MacroDef" then + error ("Unexpected type: "..t) + else + error ("Unexpected type: "..t) + end +end + + +-- filter.rel_expr("proc.name", "=", "cat") +-- filter.bool_op("and") +-- filter.nest() +-- filter.nest() +-- filter.rel_expr("fd.num", "=", "1") +-- filter.bool_op("or") +-- filter.rel_expr("fd.num", "=", "2") +-- filter.unnest() +-- filter.unnest() + +local state + + +function load_rule(r) + if (state == nil) then + state = compiler.init() + end + compiler.compile_line(r, state) +end + +function on_done() + install_filter(state.ast) +end diff --git a/lua/test.lua b/lua/test.lua index 3009c5b6..2e67ddea 100644 --- a/lua/test.lua +++ b/lua/test.lua @@ -1,4 +1,4 @@ -local compiler = require "sysdig-parser" +local compiler = require "compiler" if #arg ~= 1 then print("Usage: test.lua ") @@ -8,18 +8,19 @@ end local state = compiler.init() local function doit(line) - local ast, error_msg = compiler.compile_line(line, state) + local ast = compiler.compile_line(line, state) if not ast then print("error", error_msg) os.exit(1) end - compiler.parser.print_ast(ast) end for str in string.gmatch(arg[1], "([^;]+)") do doit(str) end +compiler.parser.print_ast(state.ast) + os.exit(0) diff --git a/userspace/digwatch/digwatch.cpp b/userspace/digwatch/digwatch.cpp index 75655ca2..0cc6f40b 100644 --- a/userspace/digwatch/digwatch.cpp +++ b/userspace/digwatch/digwatch.cpp @@ -33,7 +33,7 @@ static void usage() " -h, --help Print this page\n" " -m , --main-lua \n" " Name of lua compiler main file\n" - " (default: rules_loader.lua\n" + " (default: rules_loader.lua)\n" " -M Stop collecting after reached.\n" " -N Don't convert port numbers to names.\n" " -n , --numevents=\n" @@ -244,18 +244,18 @@ int digwatch_init(int argc, char **argv) // sinsp_evt_formatter formatter(inspector, output_format); - trim(lua_main_filename); - if (lua_main_filename.size() == 0) - { - lua_main_filename = DIGWATCH_LUA_MAIN; - } - char* env_lua_dir = getenv("DIGWATCH_LUA_DIR"); if (env_lua_dir) { lua_dir = string(env_lua_dir); } + trim(lua_main_filename); + if (lua_main_filename.size() == 0) + { + lua_main_filename = lua_dir + DIGWATCH_LUA_MAIN; + } + rules = new digwatch_rules(inspector, lua_main_filename, lua_dir); rules->load_rules(rules_file); diff --git a/userspace/digwatch/rules.cpp b/userspace/digwatch/rules.cpp index c1179bce..d8c3ecac 100644 --- a/userspace/digwatch/rules.cpp +++ b/userspace/digwatch/rules.cpp @@ -67,18 +67,18 @@ void digwatch_rules::load_rules(string rules_filename) throw sinsp_exception("can't open file " + rules_filename); } - lua_getglobal(m_ls, m_lua_compiler_cb.c_str()); + lua_getglobal(m_ls, m_lua_load_rule.c_str()); if(lua_isfunction(m_ls, -1)) { lua_pop(m_ls, 1); } else { - throw sinsp_exception("No function " + m_lua_compiler_cb + " found in lua compiler module"); + throw sinsp_exception("No function " + m_lua_load_rule + " found in lua compiler module"); } std::string line; while (std::getline(is, line)) { - lua_getglobal(m_ls, m_lua_compiler_cb.c_str()); + lua_getglobal(m_ls, m_lua_load_rule.c_str()); lua_pushstring(m_ls, line.c_str()); if(lua_pcall(m_ls, 1, 0, 0) != 0) @@ -89,6 +89,18 @@ void digwatch_rules::load_rules(string rules_filename) } } + lua_getglobal(m_ls, m_lua_on_done.c_str()); + if(lua_isfunction(m_ls, -1)) + { + if(lua_pcall(m_ls, 0, 0, 0) != 0) + { + const char* lerr = lua_tostring(m_ls, -1); + string err = "Error installing rules: " + string(lerr); + throw sinsp_exception(err); + } + } else { + throw sinsp_exception("No function " + m_lua_on_done + " found in lua compiler module"); + } } diff --git a/userspace/digwatch/rules.h b/userspace/digwatch/rules.h index cc0b0983..c46ea97f 100644 --- a/userspace/digwatch/rules.h +++ b/userspace/digwatch/rules.h @@ -17,6 +17,6 @@ class digwatch_rules lua_parser* m_lua_parser; lua_State* m_ls; - string m_lua_compiler_cb = "load_rules"; - string m_lua_; + string m_lua_load_rule = "load_rule"; + string m_lua_on_done = "on_done"; };