// -*- 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/slave_conf_tree_node.cc,v 1.32 2007/02/16 22:47:24 pavlin Exp $" #include "rtrmgr_module.h" #include "libxorp/xorp.h" #include "libxorp/xlog.h" #include "libxorp/debug.h" #include "cli.hh" #include "command_tree.hh" #include "slave_conf_tree_node.hh" #include "template_commands.hh" #include "template_tree_node.hh" #include "util.hh" extern int booterror(const char *s); SlaveConfigTreeNode::SlaveConfigTreeNode(bool verbose) : ConfigTreeNode(verbose) { } SlaveConfigTreeNode::SlaveConfigTreeNode(const string& nodename, const string &path, const TemplateTreeNode *ttn, SlaveConfigTreeNode *parent, const ConfigNodeId& node_id, uid_t user_id, uint32_t clientid, bool verbose) : ConfigTreeNode(nodename, path, ttn, parent, node_id, user_id, clientid, verbose) { } ConfigTreeNode* SlaveConfigTreeNode::create_node(const string& segment, const string& path, const TemplateTreeNode* ttn, ConfigTreeNode* parent_node, const ConfigNodeId& node_id, uid_t user_id, uint32_t clientid, bool verbose) { SlaveConfigTreeNode *new_node, *parent; parent = dynamic_cast(parent_node); // sanity check - all nodes in this tree should be Slave nodes if (parent_node != NULL) XLOG_ASSERT(parent != NULL); new_node = new SlaveConfigTreeNode(segment, path, ttn, parent, node_id, user_id, clientid, verbose); return reinterpret_cast(new_node); } ConfigTreeNode* SlaveConfigTreeNode::create_node(const ConfigTreeNode& ctn) { SlaveConfigTreeNode *new_node; const SlaveConfigTreeNode *orig; debug_msg("SlaveConfigTreeNode::create_node\n"); // sanity check - all nodes in this tree should be Slave nodes orig = dynamic_cast(&ctn); XLOG_ASSERT(orig != NULL); new_node = new SlaveConfigTreeNode(*orig); return new_node; } void SlaveConfigTreeNode::create_command_tree(CommandTree& cmd_tree, const list& cmd_names, bool include_intermediate_nodes, bool include_children_templates, bool include_leaf_value_nodes, bool include_read_only_nodes, bool include_permanent_nodes, bool include_user_hidden_nodes) const { build_command_tree(cmd_tree, cmd_names, 0, include_intermediate_nodes, include_children_templates, include_leaf_value_nodes, include_read_only_nodes, include_permanent_nodes, include_user_hidden_nodes); } bool SlaveConfigTreeNode::build_command_tree(CommandTree& cmd_tree, const list& cmd_names, int depth, bool include_intermediate_nodes, bool include_children_templates, bool include_leaf_value_nodes, bool include_read_only_nodes, bool include_permanent_nodes, bool include_user_hidden_nodes) const { bool instantiated = false; debug_msg("build_command_tree depth=%d\n", depth); if (_template_tree_node != NULL) { // XXX: ignore deprecated subtrees if (_template_tree_node->is_deprecated()) return false; // XXX: ignore user-hidden subtrees if (_template_tree_node->is_user_hidden()) return false; } if (_deleted) { debug_msg("Node %s is deleted\n", _path.c_str()); return false; } if (is_leaf_value() && (! include_leaf_value_nodes)) { // XXX: exclude leaf nodes when not needed return false; } if (depth > 0) { XLOG_ASSERT(_template_tree_node != NULL); cmd_tree.push(_segname); // // XXX: ignore read-only nodes and permanent nodes // bool include_node = true; if (is_read_only() && (! include_read_only_nodes)) include_node = false; if (is_permanent() && (! include_permanent_nodes)) include_node = false; if (is_user_hidden() && (! include_user_hidden_nodes)) include_node = false; if (include_node) { if (include_intermediate_nodes && (_template_tree_node->is_tag() == false) && (_template_tree_node->children().empty() == false)) { // // Include_intermediate_nodes indicates that we want to // include all true subtree interior nodes. This is needed // for show and edit commands, which can show or edit any // point in the hierarchy. // debug_msg("ACTIVATE NODE: %s\n", _path.c_str()); cmd_tree.instantiate(this, _template_tree_node, true /* has_command */); instantiated = true; } else { // Check to see if this node has a command that matches // what we're looking for. list::const_iterator iter; bool has_command = false; for (iter = cmd_names.begin(); iter != cmd_names.end(); ++iter) { if (_template_tree_node->const_command(*iter) != NULL) { has_command = true; break; } } if (is_leaf_value() && include_leaf_value_nodes) has_command = true; cmd_tree.instantiate(this, _template_tree_node, has_command); instantiated = true; } } } bool done = false; set templates_done; list::const_iterator iter; for (iter = _children.begin(); iter != _children.end(); ++iter) { SlaveConfigTreeNode *sctn = (SlaveConfigTreeNode*)*iter; done = sctn->build_command_tree(cmd_tree, cmd_names, depth + 1, include_intermediate_nodes, include_children_templates, include_leaf_value_nodes, include_read_only_nodes, include_permanent_nodes, include_user_hidden_nodes); if (done) { templates_done.insert(sctn->template_tree_node()); instantiated = true; } } XLOG_TRACE(_verbose, "-------\n***back at %s\n", _path.c_str()); XLOG_TRACE(_verbose, "***templates_done.size()==%u\n", XORP_UINT_CAST(templates_done.size())); XLOG_TRACE(_verbose, "***templates_done = "); if (_verbose) { string debug_output; set::const_iterator done_iter; for (done_iter = templates_done.begin(); done_iter != templates_done.end(); ++done_iter) { debug_output += c_format("%p ", *done_iter); } debug_output += "\n"; XLOG_TRACE(_verbose, "%s", debug_output.c_str()); } // // If we haven't already added the children of the template node, // we need to consider whether they can add to the command tree too. // if ((_template_tree_node != NULL) && include_children_templates) { list::const_iterator ttn_iter; for (ttn_iter = _template_tree_node->children().begin(); ttn_iter != _template_tree_node->children().end(); ++ttn_iter) { if (templates_done.find(*ttn_iter) == templates_done.end()) { XLOG_TRACE(_verbose, "***We might add TTN %s [%p] for ", (*ttn_iter)->segname().c_str(), *ttn_iter); if (_verbose) { string debug_output; list::const_iterator cmd_iter; for (cmd_iter = cmd_names.begin(); cmd_iter != cmd_names.end(); ++cmd_iter) { debug_output += c_format("%s ", cmd_iter->c_str()); } debug_output += c_format("\n*** at path %s\n", _path.c_str()); XLOG_TRACE(_verbose, "%s", debug_output.c_str()); } if ((*ttn_iter)->check_command_tree(cmd_names, include_intermediate_nodes, include_read_only_nodes, include_permanent_nodes, include_user_hidden_nodes, /* depth */ 0)) { XLOG_TRACE(_verbose, "***done == true\n"); cmd_tree.push((*ttn_iter)->segname()); cmd_tree.instantiate(NULL, (*ttn_iter), true /* has_command */); cmd_tree.pop(); instantiated = true; } else { XLOG_TRACE(_verbose, "***done == false\n"); } } } } if (depth > 0) cmd_tree.pop(); XLOG_TRACE(_verbose, "leaving build_command_tree\n"); return instantiated; } int SlaveConfigTreeNode::get_deltas(const SlaveConfigTreeNode& master_node) { int deltas = 0; XLOG_TRACE(_verbose, "get_deltas >%s<\n", _path.c_str()); if (!_deleted) { if ((!_existence_committed || !_value_committed) && (_parent != NULL)) { deltas++; XLOG_TRACE(_verbose, ">%s< CHANGED\n", _path.c_str()); } list::const_iterator iter; for (iter = master_node.const_children().begin(); iter != master_node.const_children().end(); ++iter) { SlaveConfigTreeNode* new_node; const SlaveConfigTreeNode* my_child = dynamic_cast(*iter); XLOG_ASSERT(my_child != NULL); new_node = new SlaveConfigTreeNode(*my_child); new_node->set_parent(this); add_child(new_node); deltas += ((SlaveConfigTreeNode*)new_node)-> get_deltas(*(const SlaveConfigTreeNode*)my_child); } } else { XLOG_TRACE(_verbose, ">%s< was deleted\n", _path.c_str()); } if ((deltas == 0) && (_parent != NULL)) { XLOG_TRACE(_verbose, "removing >%s<\n", _path.c_str()); delete_subtree_silently(); // XXX: will delete 'this' as well } return deltas; } int SlaveConfigTreeNode::get_deletions(const SlaveConfigTreeNode& master_node) { int deletions = 0; XLOG_TRACE(_verbose, "get_deletions >%s<\n", _path.c_str()); if ((! master_node.deleted()) || (_template_tree_node != NULL && is_tag())) { list::const_iterator iter; for (iter = master_node.const_children().begin(); iter != master_node.const_children().end(); ++iter) { SlaveConfigTreeNode* new_node; const SlaveConfigTreeNode* my_child = dynamic_cast(*iter); XLOG_ASSERT(my_child != NULL); new_node = new SlaveConfigTreeNode(*my_child); new_node->set_parent(this); new_node->undelete(); add_child(new_node); deletions += ((SlaveConfigTreeNode*)new_node)-> get_deletions(*(const SlaveConfigTreeNode*)my_child); } } else { if (_existence_committed) { XLOG_TRACE(_verbose, "%s deleted\n", _path.c_str()); deletions = 1; } else { XLOG_TRACE(_verbose, "%s deleted but not committed\n", _path.c_str()); } } if ((deletions == 0) && (_parent != NULL)) { XLOG_TRACE(_verbose, "removing >%s<\n", _path.c_str()); delete_subtree_silently(); // XXX: will delete 'this' as well } return deletions; } void SlaveConfigTreeNode::finalize_commit() { debug_msg("SlaveConfigTreeNode::finalize_commit %s\n", _segname.c_str()); if (_deleted) { debug_msg("node deleted\n"); // // Delete the entire subtree. We expect a deleted node here // to have previously had its existence committed // (_existence_committed == true) but its non-existence not // previously committed (_value_committed == false) // XLOG_ASSERT(_existence_committed); XLOG_ASSERT(!_value_committed); delete_subtree_silently(); // No point in going further return; } if ((_existence_committed == false) || (_value_committed == false)) { debug_msg("node finalized\n"); _existence_committed = true; _value_committed = true; _deleted = false; _committed_value = _value; _committed_operator = _operator; _committed_user_id = _user_id; _committed_modification_time = _modification_time; } // // Note: finalize_commit may delete the child, so we need to be // careful the iterator stays valid. // list::iterator iter, prev_iter; iter = _children.begin(); while (iter != _children.end()) { prev_iter = iter; ++iter; SlaveConfigTreeNode *child = (SlaveConfigTreeNode*)(*prev_iter); child->finalize_commit(); } }