/*
* Copyright (C) 2010 Vyatta, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* 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, see .
*/
#ifndef _CSTORE_H_
#define _CSTORE_H_
#include
#include
#include
#include
#include
#include
#include
/* declare perl internal functions. just need these two so don't include
* all the perl headers.
*/
extern "C" void Perl_croak_nocontext(const char* pat, ...)
__attribute__((noreturn))
__attribute__((format(__printf__,1,2)))
__attribute__((nonnull(1)));
extern "C" void* Perl_get_context(void)
__attribute__((warn_unused_result));
#define ASSERT_IN_SESSION assert_internal(inSession(), \
"calling %s() without config session", \
__func__);
// forward decl
namespace cnode {
class CfgNode;
}
namespace commit {
class PrioNode;
}
namespace cstore { // begin namespace cstore
using namespace std;
class Cstore {
public:
Cstore() { init(); };
Cstore(string& env);
virtual ~Cstore() {};
// factory functions
static Cstore *createCstore(bool use_edit_level = false);
static Cstore *createCstore(const string& session_id, string& env);
// constants
static const string C_NODE_STATUS_DELETED;
static const string C_NODE_STATUS_ADDED;
static const string C_NODE_STATUS_CHANGED;
static const string C_NODE_STATUS_STATIC;
static const string C_ENV_EDIT_LEVEL;
static const string C_ENV_TMPL_LEVEL;
static const string C_ENV_SHELL_PROMPT;
static const string C_ENV_SHELL_CWORDS;
static const string C_ENV_SHELL_CWORD_COUNT;
static const string C_ENV_SHAPI_COMP_VALS;
static const string C_ENV_SHAPI_LCOMP_VAL;
static const string C_ENV_SHAPI_COMP_HELP;
static const string C_ENV_SHAPI_HELP_ITEMS;
static const string C_ENV_SHAPI_HELP_STRS;
static const string C_ENUM_SCRIPT_DIR;
static const string C_LOGFILE_STDOUT;
static const size_t MAX_CMD_OUTPUT_SIZE = 40960;
// for sorting
/* apparently unordered_map template does not work with "enum" type, so
* change this to simply unsigned ints to allow unifying all map types,
* i.e., "cstore::MapT".
*/
static const unsigned int SORT_DEFAULT;
static const unsigned int SORT_DEB_VERSION;
static const unsigned int SORT_NONE;
////// the public cstore interface
//// functions implemented in this base class
// these operate on template path
bool validateTmplPath(const Cpath& path_comps, bool validate_vals);
tr1::shared_ptr parseTmpl(const Cpath& path_comps,
bool validate_vals);
bool getParsedTmpl(const Cpath& path_comps, MapT& tmap,
bool allow_val = true);
void tmplGetChildNodes(const Cpath& path_comps, vector& cnodes);
/******
* functions for actual CLI operations:
* set
* delete
* activate
* deactivate
* rename
* copy
* comment
* discard
* move (currently this is only available in cfg-cmd-wrapper)
* edit-related commands (invoked from shell functions)
* completion-related (for completion script)
* session-related (setup, teardown, etc.)
* load
*
* these operate on the "working config" and the session and MUST NOT
* be used by anything other than the listed operations.
*/
// set
bool validateSetPath(const Cpath& path_comps);
bool setCfgPath(const Cpath& path_comps);
// delete
bool deleteCfgPath(const Cpath& path_comps);
// activate (actually "unmark deactivated" since it is 2-state, not 3)
bool validateActivatePath(const Cpath& path_comps);
bool unmarkCfgPathDeactivated(const Cpath& path_comps);
// deactivate
bool validateDeactivatePath(const Cpath& path_comps);
bool markCfgPathDeactivated(const Cpath& path_comps);
// rename
bool validateRenameArgs(const Cpath& args);
bool renameCfgPath(const Cpath& args);
// copy
bool validateCopyArgs(const Cpath& args);
bool copyCfgPath(const Cpath& args);
// comment
bool commentCfgPath(const Cpath& args);
// discard
bool discardChanges();
// move
bool validateMoveArgs(const Cpath& args);
bool moveCfgPath(const Cpath& args);
// edit-related
bool getEditEnv(const Cpath& path_comps, string& env);
bool getEditUpEnv(string& env);
bool getEditResetEnv(string& env);
bool editLevelAtRoot() {
return edit_level_at_root();
};
// completion-related
bool getCompletionEnv(const Cpath& comps, string& env);
void getEditLevel(Cpath& comps) {
get_edit_level(comps);
};
// session-related
virtual bool markSessionUnsaved() = 0;
virtual bool unmarkSessionUnsaved() = 0;
virtual bool sessionUnsaved() = 0;
virtual bool sessionChanged() = 0;
virtual bool setupSession() = 0;
virtual bool teardownSession() = 0;
virtual bool inSession() = 0;
// commit
bool unmarkCfgPathChanged(const Cpath& path_comps);
bool executeTmplActions(char *at_str, const Cpath& path,
const Cpath& disp_path, const vtw_node *actions,
const vtw_def *def);
bool cfgPathMarkedCommitted(const Cpath& path_comps, bool is_delete);
bool markCfgPathCommitted(const Cpath& path_comps, bool is_delete);
virtual bool clearCommittedMarkers() = 0;
virtual bool commitConfig(commit::PrioNode& pnode) = 0;
virtual bool getCommitLock() = 0;
/* note: the getCommitLock() function must guarantee lock release/cleanup
* upon process termination (either normally or abnormally). there is no
* separate call for releasing the lock.
*/
// load
bool loadFile(const char *filename);
/******
* these functions are observers of the current "working config" or
* "active config" during a config session.
* MOST users of the cstore API should be using these functions (most
* likely during a commit operation).
*
* note that these MUST NOT worry about "deactivated" state.
* for these functions, deactivated nodes are equivalent to having been
* deleted. in other words, these functions are NOT "deactivate-aware".
*
* also, the functions that can be used to observe "active config" can
* be used outside a config session as well (only when observing active
* config, of course).
*/
// observers for "working config" (by default) OR "active config"
bool cfgPathExists(const Cpath& path_comps, bool active_cfg = false);
void cfgPathGetChildNodes(const Cpath& path_comps, vector& cnodes,
bool active_cfg = false);
bool cfgPathGetValue(const Cpath& path_comps, string& value,
bool active_cfg = false);
bool cfgPathGetValues(const Cpath& path_comps, vector& values,
bool active_cfg = false);
bool cfgPathGetComment(const Cpath& path_comps, string& comment,
bool active_cfg = false);
bool cfgPathDefault(const Cpath& path_comps, bool active_cfg = false);
/* observers for working AND active configs (at the same time).
* MUST ONLY be used during config session.
*/
bool cfgPathDeleted(const Cpath& path_comps);
bool cfgPathAdded(const Cpath& path_comps);
bool cfgPathChanged(const Cpath& path_comps);
void cfgPathGetDeletedChildNodes(const Cpath& path_comps,
vector& cnodes);
void cfgPathGetDeletedValues(const Cpath& path_comps,
vector& dvals);
void cfgPathGetChildNodesStatus(const Cpath& path_comps,
MapT& cmap) {
get_child_nodes_status(path_comps, cmap, NULL);
};
void cfgPathGetChildNodesStatus(const Cpath& path_comps,
MapT& cmap,
vector& sorted_keys) {
get_child_nodes_status(path_comps, cmap, &sorted_keys);
};
/* observers for "effective config". can be used both during a config
* session and outside a config session. more detailed information
* can be found in the source file.
*/
bool cfgPathEffective(const Cpath& path_comps);
void cfgPathGetEffectiveChildNodes(const Cpath& path_comps,
vector& cnodes);
bool cfgPathGetEffectiveValue(const Cpath& path_comps, string& value);
bool cfgPathGetEffectiveValues(const Cpath& path_comps,
vector& values);
/******
* "deactivate-aware" observers of the current working or active config.
* these are the only functions that are allowed to see the "deactivate"
* state of config nodes.
*
* these functions MUST ONLY be used by operations that NEED to distinguish
* between deactivated nodes and deleted nodes. below is the list
* of operations that are allowed to use these functions:
* * configuration output (show, save, load)
*
* operations that are not on the above list MUST NOT use these
* "deactivate-aware" functions.
*
* note: the last argument "include_deactivated" for the DA functions
* is for implementation convenience and does not need to be
* passed in when calling them.
*/
// working or active config
bool cfgPathDeactivated(const Cpath& path_comps, bool active_cfg = false);
bool cfgPathMarkedDeactivated(const Cpath& path_comps,
bool active_cfg = false);
bool cfgPathExistsDA(const Cpath& path_comps, bool active_cfg = false,
bool include_deactivated = true);
void cfgPathGetChildNodesDA(const Cpath& path_comps, vector& cnodes,
bool active_cfg = false,
bool include_deactivated = true);
bool cfgPathGetValueDA(const Cpath& path_comps, string& value,
bool active_cfg = false,
bool include_deactivated = true);
bool cfgPathGetValuesDA(const Cpath& path_comps, vector& values,
bool active_cfg = false,
bool include_deactivated = true);
// working AND active configs
void cfgPathGetDeletedChildNodesDA(const Cpath& path_comps,
vector& cnodes,
bool include_deactivated = true);
void cfgPathGetDeletedValuesDA(const Cpath& path_comps,
vector& dvals,
bool include_deactivated = true);
void cfgPathGetChildNodesStatusDA(const Cpath& path_comps,
MapT& cmap) {
get_child_nodes_status_da(path_comps, cmap, NULL);
};
void cfgPathGetChildNodesStatusDA(const Cpath& path_comps,
MapT& cmap,
vector& sorted_keys) {
get_child_nodes_status_da(path_comps, cmap, &sorted_keys);
};
// util functions
static void sortNodes(vector& nvec,
unsigned int sort_alg = SORT_DEFAULT) {
sort_nodes(nvec, sort_alg);
};
/* these are internal API functions and operate on current cfg and
* tmpl paths during cstore operations. they are only used to work around
* the limitations of the original CLI library implementation and MUST NOT
* be used by anyone other than the original CLI library.
*/
char *getVarRef(const char *ref_str, vtw_type_e& type, bool from_active);
bool setVarRef(const char *ref_str, const char *value, bool to_active);
protected:
class SavePaths {
public:
virtual ~SavePaths() = 0;
};
////// functions for subclasses
static void output_user(const char *fmt, ...);
static void output_user_err(const char *fmt, ...);
static void output_internal(const char *fmt, ...);
static void exit_internal(const char *fmt, ...);
static void assert_internal(bool cond, const char *fmt, ...);
private:
////// member class
// for variable reference
class VarRef;
////// virtual
/* "path modifiers"
* note: only these functions are allowed to permanently change the paths.
* all other functions must "preserve" the paths (but can change paths
* "during" an invocation), i.e., the paths after invocation must be
* the same as before invocation.
*/
// begin path modifiers
virtual void push_tmpl_path(const char *path_comp) = 0;
virtual void push_tmpl_path_tag() = 0;
virtual void pop_tmpl_path() = 0;
virtual void pop_tmpl_path(string& last) = 0;
virtual void push_cfg_path(const char *path_comp) = 0;
virtual void pop_cfg_path() = 0;
virtual void pop_cfg_path(string& last) = 0;
virtual void append_cfg_path(const Cpath& path_comps) = 0;
virtual void reset_paths(bool to_root = false) = 0;
#if __GNUC__ < 6
virtual auto_ptr create_save_paths() = 0;
#else
virtual unique_ptr create_save_paths() = 0;
#endif
virtual bool cfg_path_at_root() = 0;
virtual bool tmpl_path_at_root() = 0;
// end path modifiers
// these operate on current tmpl path
virtual bool tmpl_node_exists() = 0;
virtual Ctemplate *tmpl_parse() = 0;
// these operate on current work path (or active with "active_cfg")
virtual bool remove_node() = 0;
virtual void get_all_child_node_names_impl(vector& cnodes,
bool active_cfg = false) = 0;
virtual void get_all_tmpl_child_node_names(vector& cnodes) = 0;
virtual bool write_value_vec(const vector& vvec,
bool active_cfg = false) = 0;
virtual bool add_node() = 0;
virtual bool rename_child_node(const char *oname, const char *nname) = 0;
virtual bool copy_child_node(const char *oname, const char *nname) = 0;
virtual bool mark_display_default() = 0;
virtual bool unmark_display_default() = 0;
virtual bool mark_deactivated() = 0;
virtual bool unmark_deactivated() = 0;
virtual bool unmark_deactivated_descendants() = 0;
virtual bool mark_changed_with_ancestors() = 0;
virtual bool unmark_changed_with_descendants() = 0;
virtual bool remove_comment() = 0;
virtual bool set_comment(const string& comment) = 0;
virtual bool discard_changes(unsigned long long& num_removed) = 0;
// observers for current work path
virtual bool cfg_node_changed() = 0;
// observers for current work path or active path
virtual bool read_value_vec(vector& vvec, bool active_cfg) = 0;
virtual bool cfg_node_exists(bool active_cfg) = 0;
virtual bool marked_deactivated(bool active_cfg) = 0;
virtual bool get_comment(string& comment, bool active_cfg) = 0;
virtual bool marked_display_default(bool active_cfg) = 0;
// observers for "edit/tmpl levels" (for "edit"-related operations)
/* note that these should be handled in the base class since they
* should not be implementation-specific. however, current definitions
* of these "levels" environment vars require filesystem-specific
* "escapes", so handle them in derived class.
*
* revisit when the env vars are redefined.
*
* these operate on current "work" or "tmpl" path, i.e., cfg/tmpl path
* needs to be set up before calling these.
*/
virtual string get_edit_level_path() = 0;
virtual string get_tmpl_level_path() = 0;
virtual void get_edit_level(Cpath& path_comps) = 0;
virtual bool edit_level_at_root() = 0;
// functions for commit operation
virtual bool marked_committed(bool is_delete) = 0;
virtual bool mark_committed(bool is_delete) = 0;
// these are for testing/debugging
virtual string cfg_path_to_str() = 0;
virtual string tmpl_path_to_str() = 0;
////// implemented
// for sorting
typedef bool (*SortFuncT)(std::string, std::string);
static MapT _sort_func_map;
static bool sort_func_deb_version(string a, string b);
static void sort_nodes(vector& nvec,
unsigned int sort_alg = SORT_DEFAULT);
// init
static bool _init;
static void init() {
if (_init) {
return;
}
_init = true;
_sort_func_map[SORT_DEB_VERSION] = &sort_func_deb_version;
}
// begin path modifiers (only these can change path permanently)
bool append_tmpl_path(const Cpath& path_comps, bool& is_tag);
bool append_tmpl_path(const Cpath& path_comps) {
bool dummy;
return append_tmpl_path(path_comps, dummy);
};
bool append_tmpl_path(const char *path_comp, bool& is_tag) {
Cpath p;
p.push(path_comp);
return append_tmpl_path(p, is_tag);
};
bool append_tmpl_path(const char *path_comp) {
bool dummy;
return append_tmpl_path(path_comp, dummy);
};
// end path modifiers
// utility function
bool contains_whitespace(const char *name);
// end utility function
// these require full path
// (note: get_parsed_tmpl also uses current tmpl path)
tr1::shared_ptr get_parsed_tmpl(const Cpath& path_comps,
bool validate_vals,
string& error);
tr1::shared_ptr get_parsed_tmpl(const Cpath& path_comps,
bool validate_vals) {
string dummy;
return get_parsed_tmpl(path_comps, validate_vals, dummy);
};
tr1::shared_ptr validate_act_deact(const Cpath& path_comps,
const char *op);
bool validate_rename_copy(const Cpath& args, const char *op);
bool conv_move_args_for_rename(const Cpath& args, Cpath& edit_path_comps,
Cpath& rn_args);
bool cfg_path_exists(const Cpath& path_comps, bool active_cfg,
bool include_deactivated);
bool set_cfg_path(const Cpath& path_comps, bool output);
void get_child_nodes_status(const Cpath& path_comps,
MapT& cmap,
vector *sorted_keys);
void get_child_nodes_status_da(const Cpath& path_comps,
MapT& cmap,
vector *sorted_keys);
// these operate on current work path (or active with "active_cfg")
bool remove_tag();
bool remove_value_from_multi(const string& value);
bool write_value(const string& value, bool active_cfg = false) {
vector vvec(1, value);
return write_value_vec(vvec, active_cfg);
};
bool add_tag(unsigned int tlimit);
bool add_value_to_multi(unsigned int mlimit, const string& value);
bool add_child_node(const string& name) {
push_cfg_path(name.c_str());
bool ret = add_node();
pop_cfg_path();
return ret;
};
void get_all_child_node_names(vector& cnodes, bool active_cfg,
bool include_deactivated);
// observers for work path or active path
bool cfg_value_exists(const string& value, bool active_cfg);
// these operate on both current tmpl and work paths
bool validate_val(const tr1::shared_ptr& def, const char *value);
bool create_default_children(const Cpath& path_comps); /* this requires
* path_comps but DOES operate on current work path.
*/
void get_edit_env(string& env);
// util functions
string get_shell_prompt(const string& level);
void shell_escape_squotes(string& str);
void print_path_vec(const char *pre, const char *post,
const Cpath& pvec, const char *quote);
// output functions
static void voutput_user(FILE *out, FILE *dout, const char *fmt,
va_list alist);
static void voutput_internal(const char *fmt, va_list alist);
static void vexit_internal(const char *fmt, va_list alist);
void getAllowedVarRef(string& astr);
};
} // end namespace cstore
#endif /* _CSTORE_H_ */