/* * 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 /* 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__); /* macros for saving/restoring paths. * note: this allows "nested" save/restore invocations but NOT recursive ones. */ #define SAVE_PATHS save_paths(&__func__) #define RESTORE_PATHS restore_paths(&__func__) using namespace std; class Cstore { public: Cstore() { init(); }; Cstore(string& env); virtual ~Cstore() {}; // types template class MapT : public tr1::unordered_map {}; // 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 = 4096; // 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 vector& path_comps, bool validate_vals); bool validateTmplPath(const vector& path_comps, bool validate_vals, vtw_def& def); bool getParsedTmpl(const vector& path_comps, MapT& tmap, bool allow_val = true); void tmplGetChildNodes(const vector& 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 vector& path_comps); bool setCfgPath(const vector& path_comps); // delete bool validateDeletePath(const vector& path_comps, vtw_def& def); bool deleteCfgPath(const vector& path_comps, const vtw_def& def); // activate (actually "unmark deactivated" since it is 2-state, not 3) bool validateActivatePath(const vector& path_comps); bool unmarkCfgPathDeactivated(const vector& path_comps); // deactivate bool validateDeactivatePath(const vector& path_comps); bool markCfgPathDeactivated(const vector& path_comps); // rename bool validateRenameArgs(const vector& args); bool renameCfgPath(const vector& args); // copy bool validateCopyArgs(const vector& args); bool copyCfgPath(const vector& args); // comment bool validateCommentArgs(const vector& args, vtw_def& def); bool commentCfgPath(const vector& args, const vtw_def& def); // discard bool discardChanges(); // move bool validateMoveArgs(const vector& args); bool moveCfgPath(const vector& args); // edit-related bool getEditEnv(const vector& path_comps, string& env); bool getEditUpEnv(string& env); bool getEditResetEnv(string& env); bool editLevelAtRoot() { return edit_level_at_root(); }; // completion-related bool getCompletionEnv(const vector& comps, string& env); void getEditLevel(vector& 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 vector& path_comps); // 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 vector& path_comps, bool active_cfg = false); void cfgPathGetChildNodes(const vector& path_comps, vector& cnodes, bool active_cfg = false); bool cfgPathGetValue(const vector& path_comps, string& value, bool active_cfg = false); bool cfgPathGetValues(const vector& path_comps, vector& values, bool active_cfg = false); bool cfgPathGetComment(const vector& path_comps, string& comment, bool active_cfg = false); bool cfgPathDefault(const vector& 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 vector& path_comps); bool cfgPathAdded(const vector& path_comps); bool cfgPathChanged(const vector& path_comps); void cfgPathGetDeletedChildNodes(const vector& path_comps, vector& cnodes); void cfgPathGetDeletedValues(const vector& path_comps, vector& dvals); void cfgPathGetChildNodesStatus(const vector& path_comps, MapT& cmap) { get_child_nodes_status(path_comps, cmap, NULL); }; void cfgPathGetChildNodesStatus(const vector& 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 vector& path_comps); void cfgPathGetEffectiveChildNodes(const vector& path_comps, vector& cnodes); bool cfgPathGetEffectiveValue(const vector& path_comps, string& value); bool cfgPathGetEffectiveValues(const vector& 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 vector& path_comps, bool active_cfg = false); bool cfgPathMarkedDeactivated(const vector& path_comps, bool active_cfg = false); bool cfgPathExistsDA(const vector& path_comps, bool active_cfg = false, bool include_deactivated = true); void cfgPathGetChildNodesDA(const vector& path_comps, vector& cnodes, bool active_cfg = false, bool include_deactivated = true); bool cfgPathGetValueDA(const vector& path_comps, string& value, bool active_cfg = false, bool include_deactivated = true); bool cfgPathGetValuesDA(const vector& path_comps, vector& values, bool active_cfg = false, bool include_deactivated = true); // working AND active configs void cfgPathGetDeletedChildNodesDA(const vector& path_comps, vector& cnodes, bool include_deactivated = true); void cfgPathGetDeletedValuesDA(const vector& path_comps, vector& dvals, bool include_deactivated = true); void cfgPathGetChildNodesStatusDA(const vector& path_comps, MapT& cmap) { get_child_nodes_status_da(path_comps, cmap, NULL); }; void cfgPathGetChildNodesStatusDA(const vector& 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 string& ref_str, vtw_type_e& type, bool from_active); bool setVarRef(const string& ref_str, const string& value, bool to_active); protected: ////// 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 string& path_comp) = 0; virtual void push_tmpl_path_tag() = 0; virtual string pop_tmpl_path() = 0; virtual void push_cfg_path(const string& path_comp) = 0; virtual void push_cfg_path_val() = 0; virtual string pop_cfg_path() = 0; virtual void append_cfg_path(const vector& path_comps) = 0; virtual void reset_paths() = 0; virtual void save_paths(const void *handle = NULL) = 0; virtual void restore_paths(const void *handle = NULL) = 0; 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 bool tmpl_parse(vtw_def& def) = 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 string& oname, const string& nname) = 0; virtual bool copy_child_node(const string& oname, const string& 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 during commit operation virtual bool marked_committed(const vtw_def& def, bool is_set) = 0; // these operate on both current tmpl and work paths virtual bool validate_val_impl(vtw_def *def, char *value) = 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(vector& path_comps) = 0; virtual bool edit_level_at_root() = 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 vector& path_comps, bool& is_tag); bool append_tmpl_path(const vector& path_comps) { bool dummy; return append_tmpl_path(path_comps, dummy); }; bool append_tmpl_path(const string& path_comp, bool& is_tag) { return append_tmpl_path(vector(1, path_comp), is_tag); }; bool append_tmpl_path(const string& path_comp) { bool dummy; return append_tmpl_path(path_comp, dummy); }; // end path modifiers // these require full path // (note: get_parsed_tmpl also uses current tmpl path) bool get_parsed_tmpl(const vector& path_comps, bool validate_vals, vtw_def& def, string& error); bool get_parsed_tmpl(const vector& path_comps, bool validate_vals, vtw_def& def) { string dummy; return get_parsed_tmpl(path_comps, validate_vals, def, dummy); }; bool validate_act_deact(const vector& path_comps, const string& op, vtw_def& def); bool validate_rename_copy(const vector& args, const string& op); bool conv_move_args_for_rename(const vector& args, vector& edit_path_comps, vector& rn_args); bool cfg_path_exists(const vector& path_comps, bool active_cfg, bool include_deactivated); bool set_cfg_path(const vector& path_comps, bool output); void get_child_nodes_status(const vector& path_comps, Cstore::MapT& cmap, vector *sorted_keys); void get_child_nodes_status_da(const vector& path_comps, Cstore::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(const vtw_def& def); bool add_value_to_multi(const vtw_def& def, const string& value); bool add_child_node(const string& name) { push_cfg_path(name); 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 vtw_def *def, const string& value); bool create_default_children(); void get_edit_env(string& env); // util functions string get_shell_prompt(const string& level); void shell_escape_squotes(string& str); void print_str_vec(const char *pre, const char *post, const vector& vec, 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); }; #endif /* _CSTORE_H_ */