diff --git a/src/scan.l b/src/scan.l index 249a55ef0d..29105eae7e 100644 --- a/src/scan.l +++ b/src/scan.l @@ -9,6 +9,7 @@ #include #include #include +#include #include "input.h" #include "util.h" @@ -39,6 +40,7 @@ int line_number = 1; const char* filename = 0; BroDoc* current_reST_doc = 0; static BroDoc* last_reST_doc = 0; +string current_scanned_file_path; char last_tok[128]; @@ -102,6 +104,7 @@ public: int line; int level; BroDoc* doc; + string path; }; // A stack of input buffers we're scanning. file_stack[len-1] is the @@ -613,6 +616,10 @@ static int load_files_with_prefix(const char* orig_file) else file_stack.append(new FileInfo); + char* tmp = copy_string(full_filename); + current_scanned_file_path = dirname(tmp); + delete [] tmp; + if ( generate_documentation ) { current_reST_doc = new BroDoc(bropath_subpath, full_filename); @@ -895,6 +902,7 @@ FileInfo::FileInfo(string arg_restore_module) name = ::filename; line = ::line_number; doc = ::current_reST_doc; + path = current_scanned_file_path; } FileInfo::~FileInfo() @@ -907,6 +915,7 @@ FileInfo::~FileInfo() yylloc.first_line = yylloc.last_line = line_number = line; last_reST_doc = current_reST_doc; current_reST_doc = doc; + current_scanned_file_path = path; if ( restore_module != "" ) current_module = restore_module; diff --git a/src/util.cc b/src/util.cc index 31895874c9..824010a28f 100644 --- a/src/util.cc +++ b/src/util.cc @@ -868,11 +868,20 @@ void get_policy_subpath(const char* dir, const char* file, const char** subpath) delete [] tmp; } +extern string current_scanned_file_path; + FILE* search_for_file(const char* filename, const char* ext, const char** full_filename, bool load_pkgs, const char** bropath_subpath) { - if ( filename[0] == '/' || filename[0] == '.' ) + // If the file is a literal absolute path we don't have to search, + // just return the result of trying to open it. If the file is + // might be a relative path, check first if it's a real file that + // can be referenced from cwd, else we'll try to search for it based + // on what path the currently-loading script is in as well as the + // standard BROPATH paths. + if ( filename[0] == '/' || + (filename[0] == '.' && access(filename, R_OK) == 0) ) { if ( bropath_subpath ) { @@ -886,6 +895,12 @@ FILE* search_for_file(const char* filename, const char* ext, char path[1024], full_filename_buf[1024]; safe_strncpy(path, bro_path(), sizeof(path)); + // append the currently loading script's path to BROPATH so that + // @loads can be referenced relatively + if ( current_scanned_file_path != "" ) + safe_snprintf(path, sizeof(path), "%s:%s", path, + current_scanned_file_path.c_str()); + char* dir_beginning = path; char* dir_ending = path; int more = *dir_beginning != '\0'; diff --git a/testing/btest/Baseline/core.load-relative/output b/testing/btest/Baseline/core.load-relative/output new file mode 100644 index 0000000000..daff17a4e1 --- /dev/null +++ b/testing/btest/Baseline/core.load-relative/output @@ -0,0 +1,3 @@ +bar loaded +baz loaded +foo loaded diff --git a/testing/btest/core/load-relative.bro b/testing/btest/core/load-relative.bro new file mode 100644 index 0000000000..7f08f440b7 --- /dev/null +++ b/testing/btest/core/load-relative.bro @@ -0,0 +1,10 @@ +# A test of relative-path-based @load'ing + +# @TEST-EXEC: mkdir foo +# @TEST-EXEC: echo "@load ./bar" > foo/foo.bro +# @TEST-EXEC: echo "@load ../baz" >> foo/foo.bro +# @TEST-EXEC: echo 'print "foo loaded";' >> foo/foo.bro +# @TEST-EXEC: echo 'print "bar loaded";' > foo/bar.bro +# @TEST-EXEC: echo 'print "baz loaded";' > baz.bro +# @TEST-EXEC: bro foo/foo >output +# @TEST-EXEC: btest-diff output