-/******************************************************************************
- * Icinga 2 *
- * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) *
- * *
- * This program is free software; you can redistribute it and/or *
- * modify it under the terms of the GNU General Public License *
- * as published by the Free Software Foundation; either version 2 *
- * of the License, or (at your option) any later version. *
- * *
- * This program 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 this program; if not, write to the Free Software Foundation *
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
- ******************************************************************************/
+/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
#include "config/expression.hpp"
#include "config/configitem.hpp"
#include "base/exception.hpp"
#include "base/scriptglobal.hpp"
#include "base/loader.hpp"
+#include "base/reference.hpp"
+#include "base/namespace.hpp"
#include <boost/exception_ptr.hpp>
#include <boost/exception/errinfo_nested_exception.hpp>
boost::signals2::signal<void (ScriptFrame&, ScriptError *ex, const DebugInfo&)> Expression::OnBreakpoint;
boost::thread_specific_ptr<bool> l_InBreakpointHandler;
-Expression::~Expression(void)
+Expression::~Expression()
{ }
void Expression::ScriptBreakpoint(ScriptFrame& frame, ScriptError *ex, const DebugInfo& di)
frame.DecreaseStackDepth();
BOOST_THROW_EXCEPTION(ScriptError("Error while evaluating expression: " + String(ex.what()), GetDebugInfo())
- << boost::errinfo_nested_exception(boost::current_exception()));
+ << boost::errinfo_nested_exception(boost::current_exception()));
}
frame.DecreaseStackDepth();
return false;
}
-const DebugInfo& Expression::GetDebugInfo(void) const
+const DebugInfo& Expression::GetDebugInfo() const
{
static DebugInfo debugInfo;
return debugInfo;
}
-Expression *icinga::MakeIndexer(ScopeSpecifier scopeSpec, const String& index)
+std::unique_ptr<Expression> icinga::MakeIndexer(ScopeSpecifier scopeSpec, const String& index)
{
- Expression *scope = new GetScopeExpression(scopeSpec);
- return new IndexerExpression(scope, MakeLiteral(index));
+ std::unique_ptr<Expression> scope{new GetScopeExpression(scopeSpec)};
+ return std::unique_ptr<Expression>(new IndexerExpression(std::move(scope), MakeLiteral(index)));
}
-void DictExpression::MakeInline(void)
+void DictExpression::MakeInline()
{
m_Inline = true;
}
-LiteralExpression::LiteralExpression(const Value& value)
- : m_Value(value)
+LiteralExpression::LiteralExpression(Value value)
+ : m_Value(std::move(value))
{ }
ExpressionResult LiteralExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
return m_Value;
}
-const DebugInfo& DebuggableExpression::GetDebugInfo(void) const
+const DebugInfo& DebuggableExpression::GetDebugInfo() const
{
return m_DebugInfo;
}
+VariableExpression::VariableExpression(String variable, std::vector<std::shared_ptr<Expression> > imports, const DebugInfo& debugInfo)
+ : DebuggableExpression(debugInfo), m_Variable(std::move(variable)), m_Imports(std::move(imports))
+{
+ m_Imports.push_back(MakeIndexer(ScopeGlobal, "System"));
+ m_Imports.push_back(std::unique_ptr<Expression>(new IndexerExpression(MakeIndexer(ScopeGlobal, "System"), MakeLiteral("Configuration"))));
+ m_Imports.push_back(MakeIndexer(ScopeGlobal, "Types"));
+ m_Imports.push_back(MakeIndexer(ScopeGlobal, "Icinga"));
+}
+
ExpressionResult VariableExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
{
Value value;
return value;
else if (frame.Self.IsObject() && frame.Locals != frame.Self.Get<Object::Ptr>() && frame.Self.Get<Object::Ptr>()->GetOwnField(m_Variable, &value))
return value;
- else if (VMOps::FindVarImport(frame, m_Variable, &value, m_DebugInfo))
+ else if (VMOps::FindVarImport(frame, m_Imports, m_Variable, &value, m_DebugInfo))
return value;
else
return ScriptGlobal::Get(m_Variable);
*parent = frame.Locals;
if (dhint)
- *dhint = NULL;
+ *dhint = nullptr;
} else if (frame.Self.IsObject() && frame.Locals != frame.Self.Get<Object::Ptr>() && frame.Self.Get<Object::Ptr>()->HasOwnField(m_Variable)) {
*parent = frame.Self;
if (dhint && *dhint)
*dhint = new DebugHint((*dhint)->GetChild(m_Variable));
- } else if (VMOps::FindVarImportRef(frame, m_Variable, parent, m_DebugInfo)) {
+ } else if (VMOps::FindVarImportRef(frame, m_Imports, m_Variable, parent, m_DebugInfo)) {
return true;
} else if (ScriptGlobal::Exists(m_Variable)) {
*parent = ScriptGlobal::GetGlobals();
if (dhint)
- *dhint = NULL;
+ *dhint = nullptr;
} else
*parent = frame.Self;
return true;
}
+ExpressionResult RefExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
+{
+ Value parent;
+ String index;
+
+ if (!m_Operand->GetReference(frame, false, &parent, &index, &dhint))
+ BOOST_THROW_EXCEPTION(ScriptError("Cannot obtain reference for expression.", m_DebugInfo));
+
+ if (!parent.IsObject())
+ BOOST_THROW_EXCEPTION(ScriptError("Cannot obtain reference for expression because parent is not an object.", m_DebugInfo));
+
+ return new Reference(parent, index);
+}
+
+ExpressionResult DerefExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
+{
+ ExpressionResult operand = m_Operand->Evaluate(frame);
+ CHECK_RESULT(operand);
+
+ Object::Ptr obj = operand.GetValue();
+ Reference::Ptr ref = dynamic_pointer_cast<Reference>(obj);
+
+ if (!ref)
+ BOOST_THROW_EXCEPTION(ScriptError("Invalid reference specified.", GetDebugInfo()));
+
+ return ref->Get();
+}
+
+bool DerefExpression::GetReference(ScriptFrame& frame, bool init_dict, Value *parent, String *index, DebugHint **dhint) const
+{
+ ExpressionResult operand = m_Operand->Evaluate(frame);
+ if (operand.GetCode() != ResultOK)
+ return false;
+
+ Reference::Ptr ref = operand.GetValue();
+
+ *parent = ref->GetParent();
+ *index = ref->GetIndex();
+ return true;
+}
+
ExpressionResult NegateExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
{
ExpressionResult operand = m_Operand->Evaluate(frame);
if (vfunc.IsObjectType<Type>()) {
std::vector<Value> arguments;
- for (Expression *arg : m_Args) {
+ arguments.reserve(m_Args.size());
+ for (const auto& arg : m_Args) {
ExpressionResult argres = arg->Evaluate(frame);
CHECK_RESULT(argres);
BOOST_THROW_EXCEPTION(ScriptError("Function is not marked as safe for sandbox mode.", m_DebugInfo));
std::vector<Value> arguments;
- for (Expression *arg : m_Args) {
+ arguments.reserve(m_Args.size());
+ for (const auto& arg : m_Args) {
ExpressionResult argres = arg->Evaluate(frame);
CHECK_RESULT(argres);
ExpressionResult ArrayExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
{
- Array::Ptr result = new Array();
- result->Reserve(m_Expressions.size());
+ ArrayData result;
+ result.reserve(m_Expressions.size());
- for (Expression *aexpr : m_Expressions) {
+ for (const auto& aexpr : m_Expressions) {
ExpressionResult element = aexpr->Evaluate(frame);
CHECK_RESULT(element);
- result->Add(element.GetValue());
+ result.push_back(element.GetValue());
}
- return result;
+ return new Array(std::move(result));
}
ExpressionResult DictExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
Value result;
try {
- for (Expression *aexpr : m_Expressions) {
- ExpressionResult element = aexpr->Evaluate(frame, m_Inline ? dhint : NULL);
+ for (const auto& aexpr : m_Expressions) {
+ ExpressionResult element = aexpr->Evaluate(frame, m_Inline ? dhint : nullptr);
CHECK_RESULT(element);
result = element.GetValue();
}
}
}
- VMOps::SetField(parent, index, operand2.GetValue(), m_DebugInfo);
+ VMOps::SetField(parent, index, operand2.GetValue(), m_OverrideFrozen, m_DebugInfo);
if (psdhint) {
psdhint->AddMessage("=", m_DebugInfo);
return Empty;
}
+void SetExpression::SetOverrideFrozen()
+{
+ m_OverrideFrozen = true;
+}
+
+ExpressionResult SetConstExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
+{
+ auto globals = ScriptGlobal::GetGlobals();
+
+ auto attr = globals->GetAttribute(m_Name);
+
+ if (dynamic_pointer_cast<ConstEmbeddedNamespaceValue>(attr)) {
+ std::ostringstream msgbuf;
+ msgbuf << "Value for constant '" << m_Name << "' was modified. This behaviour is deprecated.\n";
+ ShowCodeLocation(msgbuf, GetDebugInfo(), false);
+ Log(LogWarning, msgbuf.str());
+ }
+
+ ExpressionResult operandres = m_Operand->Evaluate(frame);
+ CHECK_RESULT(operandres);
+ Value operand = operandres.GetValue();
+
+ globals->SetAttribute(m_Name, std::make_shared<ConstEmbeddedNamespaceValue>(operand));
+
+ return Empty;
+}
+
ExpressionResult ConditionalExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
{
ExpressionResult condition = m_Condition->Evaluate(frame, dhint);
{
Value vparent;
String vindex;
- DebugHint *psdhint = NULL;
+ DebugHint *psdhint = nullptr;
bool free_psd = false;
if (dhint)
if (m_Operand1->GetReference(frame, init_dict, &vparent, &vindex, &psdhint)) {
if (init_dict) {
- Value old_value = VMOps::GetField(vparent, vindex, frame.Sandboxed, m_Operand1->GetDebugInfo());
+ Value old_value;
+ bool has_field = true;
+
+ if (vparent.IsObject()) {
+ Object::Ptr oparent = vparent;
+ has_field = oparent->HasOwnField(vindex);
+ }
+
+ if (has_field)
+ old_value = VMOps::GetField(vparent, vindex, frame.Sandboxed, m_Operand1->GetDebugInfo());
if (old_value.IsEmpty() && !old_value.IsString())
- VMOps::SetField(vparent, vindex, new Dictionary(), m_Operand1->GetDebugInfo());
+ VMOps::SetField(vparent, vindex, new Dictionary(), m_OverrideFrozen, m_Operand1->GetDebugInfo());
}
*parent = VMOps::GetField(vparent, vindex, frame.Sandboxed, m_DebugInfo);
if (psdhint)
*dhint = new DebugHint(psdhint->GetChild(*index));
else
- *dhint = NULL;
+ *dhint = nullptr;
}
if (free_psd)
return true;
}
-void icinga::BindToScope(Expression *& expr, ScopeSpecifier scopeSpec)
+void IndexerExpression::SetOverrideFrozen()
+{
+ m_OverrideFrozen = true;
+}
+
+void icinga::BindToScope(std::unique_ptr<Expression>& expr, ScopeSpecifier scopeSpec)
{
- DictExpression *dexpr = dynamic_cast<DictExpression *>(expr);
+ auto *dexpr = dynamic_cast<DictExpression *>(expr.get());
if (dexpr) {
- for (Expression *& expr : dexpr->m_Expressions)
+ for (auto& expr : dexpr->m_Expressions)
BindToScope(expr, scopeSpec);
return;
}
- SetExpression *aexpr = dynamic_cast<SetExpression *>(expr);
+ auto *aexpr = dynamic_cast<SetExpression *>(expr.get());
if (aexpr) {
BindToScope(aexpr->m_Operand1, scopeSpec);
return;
}
- IndexerExpression *iexpr = dynamic_cast<IndexerExpression *>(expr);
+ auto *iexpr = dynamic_cast<IndexerExpression *>(expr.get());
if (iexpr) {
BindToScope(iexpr->m_Operand1, scopeSpec);
return;
}
- LiteralExpression *lexpr = dynamic_cast<LiteralExpression *>(expr);
+ auto *lexpr = dynamic_cast<LiteralExpression *>(expr.get());
if (lexpr && lexpr->GetValue().IsString()) {
- Expression *scope = new GetScopeExpression(scopeSpec);
- expr = new IndexerExpression(scope, lexpr, lexpr->GetDebugInfo());
+ std::unique_ptr<Expression> scope{new GetScopeExpression(scopeSpec)};
+ expr.reset(new IndexerExpression(std::move(scope), std::move(expr), lexpr->GetDebugInfo()));
}
- VariableExpression *vexpr = dynamic_cast<VariableExpression *>(expr);
+ auto *vexpr = dynamic_cast<VariableExpression *>(expr.get());
if (vexpr) {
- Expression *scope = new GetScopeExpression(scopeSpec);
- Expression *new_expr = new IndexerExpression(scope, MakeLiteral(vexpr->GetVariable()), vexpr->GetDebugInfo());
- delete expr;
- expr = new_expr;
+ std::unique_ptr<Expression> scope{new GetScopeExpression(scopeSpec)};
+ expr.reset(new IndexerExpression(std::move(scope), MakeLiteral(vexpr->GetVariable()), vexpr->GetDebugInfo()));
}
}
if (!name.IsString())
BOOST_THROW_EXCEPTION(ScriptError("Template/object name must be a string", m_DebugInfo));
- ConfigItem::Ptr item = ConfigItem::GetByTypeAndName(type, name);
+ ConfigItem::Ptr item = ConfigItem::GetByTypeAndName(Type::GetByName(type), name);
if (!item)
BOOST_THROW_EXCEPTION(ScriptError("Import references unknown template: '" + name + "'", m_DebugInfo));
BOOST_THROW_EXCEPTION(ScriptError("Imports are not allowed in sandbox mode.", m_DebugInfo));
String type = VMOps::GetField(frame.Self, "type", frame.Sandboxed, m_DebugInfo);
+ Type::Ptr ptype = Type::GetByName(type);
- for (const ConfigItem::Ptr& item : ConfigItem::GetDefaultTemplates(type)) {
+ for (const ConfigItem::Ptr& item : ConfigItem::GetDefaultTemplates(ptype)) {
Dictionary::Ptr scope = item->GetScope();
if (scope)
CHECK_RESULT(nameres);
return VMOps::NewApply(frame, m_Type, m_Target, nameres.GetValue(), m_Filter,
- m_Package, m_FKVar, m_FVVar, m_FTerm, m_ClosedVars, m_IgnoreOnError, m_Expression, m_DebugInfo);
+ m_Package, m_FKVar, m_FVVar, m_FTerm, m_ClosedVars, m_IgnoreOnError, m_Expression, m_DebugInfo);
+}
+
+ExpressionResult NamespaceExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
+{
+ Namespace::Ptr ns = new Namespace(new ConstNamespaceBehavior());
+
+ ScriptFrame innerFrame(true, ns);
+ ExpressionResult result = m_Expression->Evaluate(innerFrame);
+ CHECK_RESULT(result);
+
+ return ns;
}
ExpressionResult ObjectExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
if (frame.Sandboxed)
BOOST_THROW_EXCEPTION(ScriptError("Object definitions are not allowed in sandbox mode.", m_DebugInfo));
+ ExpressionResult typeres = m_Type->Evaluate(frame, dhint);
+ CHECK_RESULT(typeres);
+ Type::Ptr type = typeres.GetValue();
+
String name;
if (m_Name) {
name = nameres.GetValue();
}
- return VMOps::NewObject(frame, m_Abstract, m_Type, name, m_Filter, m_Zone,
- m_Package, m_DefaultTmpl, m_IgnoreOnError, m_ClosedVars, m_Expression, m_DebugInfo);
+ return VMOps::NewObject(frame, m_Abstract, type, name, m_Filter, m_Zone,
+ m_Package, m_DefaultTmpl, m_IgnoreOnError, m_ClosedVars, m_Expression, m_DebugInfo);
}
ExpressionResult ForExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
ExpressionResult libres = m_Operand->Evaluate(frame, dhint);
CHECK_RESULT(libres);
- Loader::LoadExtensionLibrary(libres.GetValue());
+ Log(LogNotice, "config")
+ << "Ignoring explicit load request for library \"" << libres << "\".";
return Empty;
}
if (frame.Sandboxed)
BOOST_THROW_EXCEPTION(ScriptError("Includes are not allowed in sandbox mode.", m_DebugInfo));
- Expression *expr;
+ std::unique_ptr<Expression> expr;
String name, path, pattern;
switch (m_Type) {
try {
res = expr->Evaluate(frame, dhint);
} catch (const std::exception&) {
- delete expr;
throw;
}
- delete expr;
-
return res;
}
ExpressionResult BreakpointExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
{
- ScriptBreakpoint(frame, NULL, GetDebugInfo());
+ ScriptBreakpoint(frame, nullptr, GetDebugInfo());
return Empty;
}
-ExpressionResult UsingExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
+ExpressionResult TryExceptExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
{
- if (frame.Sandboxed)
- BOOST_THROW_EXCEPTION(ScriptError("Using directives are not allowed in sandbox mode.", m_DebugInfo));
-
- ExpressionResult importres = m_Name->Evaluate(frame);
- CHECK_RESULT(importres);
- Value import = importres.GetValue();
-
- if (!import.IsObjectType<Dictionary>())
- BOOST_THROW_EXCEPTION(ScriptError("The parameter must resolve to an object of type 'Dictionary'", m_DebugInfo));
-
- ScriptFrame::AddImport(import);
+ try {
+ ExpressionResult tryResult = m_TryBody->Evaluate(frame, dhint);
+ CHECK_RESULT(tryResult);
+ } catch (const std::exception&) {
+ ExpressionResult exceptResult = m_ExceptBody->Evaluate(frame, dhint);
+ CHECK_RESULT(exceptResult);
+ }
return Empty;
}