// -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*- // Copyright (c) 2001-2007 International Computer Science Institute // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software") // to deal in the Software without restriction, subject to the conditions // listed in the XORP LICENSE file. These conditions include: you must // preserve this copyright notice, and you cannot mention the copyright // holders in advertising related to the Software without their permission. // The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This // notice is a summary of the XORP LICENSE file; the license in that file is // legally binding. #ident "$XORP: xorp/rtrmgr/xrldb.cc,v 1.19 2007/02/16 22:47:28 pavlin Exp $" #include "rtrmgr_module.h" #include "libxorp/xorp.h" #include "libxorp/xlog.h" #include "libxorp/debug.h" #include "libxorp/exceptions.hh" #include "libxorp/utils.hh" #ifdef HAVE_GLOB_H #include #elif defined(HOST_OS_WINDOWS) #include "glob_win32.h" #endif #include "libxipc/xrl_parser.hh" #include "xrldb.hh" #ifdef HOST_OS_WINDOWS #define stat _stat #define S_IFDIR _S_IFDIR #endif XrlSpec::XrlSpec(const Xrl& xrl, const XrlArgs& rspec, bool verbose) : _xrl(xrl), _rspec(rspec), _verbose(verbose) { debug_msg("XrlSpec %s -> %s\n", xrl.str().c_str(), rspec.str().c_str()); } XRLMatchType XrlSpec::matches(const Xrl& xrl, const XrlArgs& rspec) const { debug_msg("------\n"); debug_msg("TEST: %s -> %s\n", xrl.str().c_str(), rspec.str().c_str()); debug_msg("DB: %s -> %s\n", _xrl.str().c_str(), _rspec.str().c_str()); if (xrl == _xrl) debug_msg("XRL matches\n"); if (rspec == _rspec) debug_msg("RSPEC matches\n"); XRLMatchType m = MATCH_FAIL; if (xrl == _xrl) { m = XRLMatchType(m | MATCH_XRL); } if (rspec == _rspec) { m = XRLMatchType(m | MATCH_RSPEC); } return m; } string XrlSpec::str() const { string s = _xrl.str() + " -> " + _rspec.str(); return s; } XRLtarget::XRLtarget(const string& xrlfilename, bool verbose) : _targetname(xrlfilename), _verbose(verbose) { debug_msg("Loading xrl file %s\n", xrlfilename.c_str()); XrlParserFileInput xpi(xrlfilename.c_str()); XrlParser parser(xpi); while (parser.start_next()) { string s; XrlArgs rargs; list rspec; try { if (parser.get(s)) { debug_msg("Xrl %s\n", s.c_str()); if (parser.get_return_specs(rspec)) { debug_msg("Return Spec:\n"); list::const_iterator si; for (si = rspec.begin(); si != rspec.end(); si++) { rargs.add(si->atom()); debug_msg("\t -> %s - %s\n", si->atom().str().c_str(), si->spell().c_str()); } } else { debug_msg("No return spec for XRL %s\n", s.c_str()); } Xrl xrl(s.c_str()); _xrlspecs.push_back(XrlSpec(xrl, rargs, _verbose)); } } catch (const XrlParseError& xpe) { s = string(79, '-') + "\n"; s += xpe.pretty_print() + "\n"; s += string(79, '=') + "\n"; s += "Attempting resync..."; if (parser.resync()) s += "okay"; else s += "fail"; s += "\n"; XLOG_ERROR("%s", s.c_str()); } catch (const InvalidString& is) { XLOG_ERROR("%s\n", is.str().c_str()); } } } XRLMatchType XRLtarget::xrl_matches(const Xrl& xrl, const XrlArgs& rspec) const { list::const_iterator iter; XRLMatchType match; XRLMatchType failure_type = MATCH_FAIL; for (iter = _xrlspecs.begin(); iter != _xrlspecs.end(); ++iter) { match = iter->matches(xrl, rspec); if (match == MATCH_ALL) return MATCH_ALL; if (match == MATCH_XRL) failure_type = MATCH_XRL; } return failure_type; } string XRLtarget::str() const { string s = " Target " + _targetname + ":\n"; list::const_iterator iter; for (iter = _xrlspecs.begin(); iter != _xrlspecs.end(); ++iter) { s += " " + iter->str() + "\n"; } return s; } XRLdb::XRLdb(const string& xrldir, bool verbose) throw (InitError) : _verbose(verbose) { string errmsg; list files; struct stat dirdata; if (stat(xrldir.c_str(), &dirdata) < 0) { errmsg = c_format("Error reading XRL directory %s: %s", xrldir.c_str(), strerror(errno)); xorp_throw(InitError, errmsg); } if ((dirdata.st_mode & S_IFDIR) == 0) { errmsg = c_format("Error reading XRL directory %s: not a directory", xrldir.c_str()); xorp_throw(InitError, errmsg); } // TODO: file suffix is hardcoded here! string globname = xrldir + PATH_DELIMITER_STRING + "*.xrls"; glob_t pglob; if (glob(globname.c_str(), 0, 0, &pglob) != 0) { globfree(&pglob); errmsg = c_format("Failed to find XRL files in %s", xrldir.c_str()); xorp_throw(InitError, errmsg); } if (pglob.gl_pathc == 0) { globfree(&pglob); errmsg = c_format("Failed to find any XRL files in %s", xrldir.c_str()); xorp_throw(InitError, errmsg); } for (size_t i = 0; i < (size_t)pglob.gl_pathc; i++) { _targets.push_back(XRLtarget(pglob.gl_pathv[i], _verbose)); } globfree(&pglob); debug_msg("XRLdb initialized\n"); debug_msg("%s\n", str().c_str()); } bool XRLdb::check_xrl_syntax(const string& xrlstr) const { debug_msg("XRLdb: checking xrl syntax: %s\n", xrlstr.c_str()); try { string::size_type start = xrlstr.find("->"); string rspec; string xrlspec; if (start == string::npos) { rspec.empty(); xrlspec = xrlstr; } else { xrlspec = xrlstr.substr(0, start); rspec = xrlstr.substr(start+2, xrlstr.size()-(start+2)); } Xrl test_xrl(xrlspec.c_str()); XrlArgs test_atoms(rspec.c_str()); } catch (const InvalidString&) { return false; } return true; } XRLMatchType XRLdb::check_xrl_exists(const string& xrlstr) const { debug_msg("XRLdb: checking xrl exists: %s\n", xrlstr.c_str()); string::size_type start = xrlstr.find("->"); string xrlspec; string rspec; if (start == string::npos) { xrlspec = xrlstr; rspec.empty(); } else { xrlspec = xrlstr.substr(0, start); rspec = xrlstr.substr(start + 2, xrlstr.size() - (start + 2)); } Xrl test_xrl(xrlspec.c_str()); XrlArgs test_atoms(rspec.c_str()); XRLMatchType match; XRLMatchType failure_type = MATCH_FAIL; list::const_iterator iter; for (iter = _targets.begin(); iter != _targets.end(); ++iter) { match = iter->xrl_matches(test_xrl, test_atoms); if (match == MATCH_ALL) return MATCH_ALL; if (match == MATCH_XRL) failure_type = MATCH_XRL; } return failure_type; } string XRLdb::str() const { string s = "XRLdb contains\n"; list::const_iterator iter; for (iter = _targets.begin(); iter != _targets.end(); ++iter) { s += iter->str() + "\n"; } return s; }