diff --git a/src/zeek.bif b/src/zeek.bif index e3b1f5caa6..18ffb101bd 100644 --- a/src/zeek.bif +++ b/src/zeek.bif @@ -5328,3 +5328,35 @@ function table_pattern_matcher_stats%(tbl: any%) : MatcherStats return std::move(result); %} + +## Determine the path used by a non-relative @load directive. +## +## This function is package aware: Passing *package* will yield the +## path to *package.zeek*, *package/__load__.zeek* or an empty string +## if neither can be found. Note that passing a relative path or absolute +## path is an error. +## +## path: The filename, package or path to search for in ZEEKPATH. +## +## Returns: Path of script file that would be loaded by an @load directive. +function find_in_zeekpath%(p: string%): string + %{ + auto path = p->ToStdString(); + if ( ! path.empty() && (path[0] == '.' || path[0] == '/') ) + { + zeek::reporter->Error("find_in_zeek_path: path must be relative or absolute"); + return zeek::val_mgr->EmptyString(); + } + + auto resolved = zeek::util::find_script_file(path, zeek::util::zeek_path()); + if ( ! resolved.empty() && zeek::util::is_dir(resolved.c_str()) ) + { + // If it's a directory, try opening the package using + // the absolute path. This is zeek::util::open_package() + // without the noisy error log. + resolved.append("/__load__.zeek"); + resolved = zeek::util::find_file(resolved, ""); + } + + return zeek::make_intrusive(resolved.c_str()); + %} diff --git a/testing/btest/Baseline/bifs.find_in_zeekpath/.stderr b/testing/btest/Baseline/bifs.find_in_zeekpath/.stderr new file mode 100644 index 0000000000..49d861c74c --- /dev/null +++ b/testing/btest/Baseline/bifs.find_in_zeekpath/.stderr @@ -0,0 +1 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. diff --git a/testing/btest/Baseline/bifs.find_in_zeekpath/errors.stderr b/testing/btest/Baseline/bifs.find_in_zeekpath/errors.stderr new file mode 100644 index 0000000000..6ac968308b --- /dev/null +++ b/testing/btest/Baseline/bifs.find_in_zeekpath/errors.stderr @@ -0,0 +1,3 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +error: find_in_zeek_path: path must be relative or absolute +error: find_in_zeek_path: path must be relative or absolute diff --git a/testing/btest/Baseline/bifs.find_in_zeekpath/errors.stdout b/testing/btest/Baseline/bifs.find_in_zeekpath/errors.stdout new file mode 100644 index 0000000000..0c8d6fd0fd --- /dev/null +++ b/testing/btest/Baseline/bifs.find_in_zeekpath/errors.stdout @@ -0,0 +1,3 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +relative, +absolute, diff --git a/testing/btest/Baseline/bifs.find_in_zeekpath/out b/testing/btest/Baseline/bifs.find_in_zeekpath/out new file mode 100644 index 0000000000..878b9c6d19 --- /dev/null +++ b/testing/btest/Baseline/bifs.find_in_zeekpath/out @@ -0,0 +1,10 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +find_in_zeekpath base/protocols/conn, base/protocols/conn/__load__.zeek +find_in_zeekpath protocols/conn (empty expected, no __load__.zeek), +find_in_zeekpath protocols/conn/vlan-logging, policy/protocols/conn/vlan-logging.zeek +find_in_zeekpath pkg1, ./pkg1.zeek +find_in_zeekpath pkg1.zeek, ./pkg1.zeek +find_in_zeekpath pkg2, ./pkg2/__load__.zeek +find_in_zeekpath pkg3, +pkg1! +pkg2! diff --git a/testing/btest/bifs/find_in_zeekpath.zeek b/testing/btest/bifs/find_in_zeekpath.zeek new file mode 100644 index 0000000000..bc212cb15c --- /dev/null +++ b/testing/btest/bifs/find_in_zeekpath.zeek @@ -0,0 +1,59 @@ +# @TEST-DOC: Test find_in_zeekpath() and demo conditional @load'ing. +# +# @TEST-EXEC: zeek -b %INPUT >out +# @TEST-EXEC: btest-diff out +# @TEST-EXEC: btest-diff .stderr +# +# @TEST-EXEC: zeek -b errors.zeek >errors.stdout 2>errors.stderr +# @TEST-EXEC: btest-diff errors.stdout +# @TEST-EXEC: btest-diff errors.stderr + + +@if ( find_in_zeekpath("pkg1") != "" ) +@load pkg1 +@endif + +@if ( find_in_zeekpath("pkg2") != "" ) +@load pkg2 +@endif + +@if ( find_in_zeekpath("pkg3") != "" ) +@load pkg3 +@endif + +function path_tail(r: string): string + { + if ( |r| == 0 ) + return r; + local parts = split_string(r, /\//); + return join_string_vec(parts[-4:], "/"); + } + +print "find_in_zeekpath base/protocols/conn", path_tail(find_in_zeekpath("base/protocols/conn")); +print "find_in_zeekpath protocols/conn (empty expected, no __load__.zeek)", find_in_zeekpath("protocols/conn"); +print "find_in_zeekpath protocols/conn/vlan-logging", path_tail(find_in_zeekpath("protocols/conn/vlan-logging")); + +print "find_in_zeekpath pkg1", find_in_zeekpath("pkg1"); +print "find_in_zeekpath pkg1.zeek", find_in_zeekpath("pkg1.zeek"); +print "find_in_zeekpath pkg2", find_in_zeekpath("pkg2"); +print "find_in_zeekpath pkg3", find_in_zeekpath("pkg3"); + +@TEST-START-FILE pkg1.zeek +event zeek_init() + { + print "pkg1!"; + } +@TEST-END-FILE + +@TEST-START-FILE pkg2/__load__.zeek +event zeek_init() + { + print "pkg2!"; + } +@TEST-END-FILE + +@TEST-START-FILE errors.zeek +# Using relative and absolute paths is an error (empty string) +print "relative", find_in_zeekpath("./pkg1.zeek"); +print "absolute", find_in_zeekpath("/pkg1"); +@TEST-END-FILE