/******************************************************************** * FUNCTION grp_has_typedefs * * Check if the grouping contains any typedefs * * INPUTS: * grp == grp_template_t struct to check * * RETURNS: * TRUE if any embedded typedefs * FALSE if no embedded typedefs *********************************************************************/ boolean grp_has_typedefs (const grp_template_t *grp) { const grp_template_t *chgrp; #ifdef DEBUG if (!grp) { SET_ERROR(ERR_INTERNAL_PTR); return FALSE; } #endif if (!dlq_empty(&grp->typedefQ)) { return TRUE; } for (chgrp = (const grp_template_t *) dlq_firstEntry(&grp->groupingQ); chgrp != NULL; chgrp = (const grp_template_t *)dlq_nextEntry(chgrp)) { if (grp_has_typedefs(chgrp)) { return TRUE; } } return FALSE; } /* grp_has_typedefs */
/******************************************************************** * FUNCTION rpc_err_clean_record * * Clean an rpc_err_rec_t struct * * INPUTS: * err == rpc_err_rec_t struct to clean * RETURNS: * none *********************************************************************/ void rpc_err_clean_record (rpc_err_rec_t *err) { rpc_err_info_t *errinfo; #ifdef DEBUG if (!err) { SET_ERROR(ERR_INTERNAL_PTR); return; } #endif err->error_res = NO_ERR; err->error_id = RPC_ERR_NONE; err->error_type = NCX_LAYER_NONE; err->error_severity = RPC_ERR_SEV_NONE; err->error_tag = NULL; err->error_app_tag = NULL; if (err->error_path) { m__free(err->error_path); err->error_path = NULL; } if (err->error_message) { m__free(err->error_message); } err->error_message_lang = NULL; while (!dlq_empty(&err->error_info)) { errinfo = (rpc_err_info_t *)dlq_deque(&err->error_info); rpc_err_free_info(errinfo); } } /* rpc_err_clean_record */
/******************************************************************** * FUNCTION rpc_free_msg * * Free all the memory used by the specified rpc_msg_t * * INPUTS: * msg == rpc_msg_t to clean and delete * RETURNS: * none *********************************************************************/ void rpc_free_msg (rpc_msg_t *msg) { if (!msg) { return; } xml_msg_clean_hdr(&msg->mhdr); //msg->rpc_in_attrs = NULL; //msg->rpc_method = NULL; //msg->rpc_agt_state = 0; /* clean input parameter set */ if (msg->rpc_input) { val_free_value(msg->rpc_input); } //msg->rpc_user1 = NULL; //msg->rpc_user2 = NULL; //msg->rpc_filter.op_filtyp = OP_FILTER_NONE; //msg->rpc_filter.op_filter = NULL; //msg->rpc_datacb = NULL; /* clean data queue */ while (!dlq_empty(&msg->rpc_dataQ)) { val_value_t *val = (val_value_t *)dlq_deque(&msg->rpc_dataQ); val_free_value(val); } m__free(msg); } /* rpc_free_msg */
/******************************************************************** * FUNCTION yangapi_clean_keyvalQ * * Free all the YANGAPI keyval * * INPUTS: * rcb == control block to use * RETURNS: * none *********************************************************************/ void yangapi_clean_keyvalQ (yangapi_cb_t *rcb) { while (!dlq_empty(&rcb->keyvalQ)) { yangapi_keyval_t *kv = (yangapi_keyval_t *) dlq_deque(&rcb->keyvalQ); yangapi_free_keyval(kv); } } /* yangapi_clean_keyvalQ */
/******************************************************************** * FUNCTION agt_cfg_free_transaction * * Clean and free a agt_cfg_transaction_t struct * * INPUTS: * txcb == transaction struct to free *********************************************************************/ void agt_cfg_free_transaction (agt_cfg_transaction_t *txcb) { if (txcb == NULL) { return; } /* clear current config txid if any */ if (txcb->txid) { cfg_template_t *cfg = cfg_get_config_id(txcb->cfg_id); if (cfg) { if (cfg->cur_txid == txcb->txid) { log_debug3("\nClearing current txid for %s config", cfg->name); cfg->cur_txid = 0; } } } /* clean undo queue */ while (!dlq_empty(&txcb->undoQ)) { agt_cfg_undo_rec_t *undorec = (agt_cfg_undo_rec_t *) dlq_deque(&txcb->undoQ); agt_cfg_free_undorec(undorec); } /* clean audit queue */ while (!dlq_empty(&txcb->auditQ)) { agt_cfg_audit_rec_t *auditrec = (agt_cfg_audit_rec_t *) dlq_deque(&txcb->auditQ); agt_cfg_free_auditrec(auditrec); } /* clean dead node queue */ while (!dlq_empty(&txcb->deadnodeQ)) { agt_cfg_nodeptr_t *nodeptr = (agt_cfg_nodeptr_t *) dlq_deque(&txcb->deadnodeQ); agt_cfg_free_nodeptr(nodeptr); } m__free(txcb); } /* agt_cfg_free_transaction */
/******************************************************************** * Clean a queue of grp_template_t structs * * \param que Q of grp_template_t data structures to free *********************************************************************/ void grp_clean_groupingQ (dlq_hdr_t *que) { if (!que) { return; } while (!dlq_empty(que)) { grp_template_t *grp = (grp_template_t *)dlq_deque(que); grp_free_template(grp); } } /* grp_clean_groupingQ */
/******************************************************************** * FUNCTION free_aliases * * Free all the command aliases * *********************************************************************/ void free_aliases (void) { dlq_hdr_t *aliasQ = get_aliasQ(); alias_cb_t *alias; while (!dlq_empty(aliasQ)) { alias = (alias_cb_t *)dlq_deque(aliasQ); free_alias(alias); } } /* free_aliases */
/******************************************************************** * FUNCTION yangcli_notif_cleanup * * Cleanup this module * *********************************************************************/ void yangcli_notif_cleanup (void) { if (yangcli_notif_init_done) { while (!dlq_empty(&event_cbQ)) { event_cb_t *cb = dlq_deque(&event_cbQ); free_event_cb(cb); } yangcli_notif_init_done = FALSE; } } /* yangcli_notif_cleanup */
/******************************************************************** * FUNCTION rpc_err_any_errors * * Check if there are any errors in the RPC message error Q * * INPUTS: * msg == rpc_msg_t struct to check for errors * * RETURNS: * TRUE if any errors recorded; FALSE if none *********************************************************************/ boolean rpc_err_any_errors (const rpc_msg_t *msg) { #ifdef DEBUG if (!msg) { SET_ERROR(ERR_INTERNAL_PTR); return FALSE; } #endif return (dlq_empty(&msg->mhdr.errQ)) ? FALSE : TRUE; } /* rpc_err_any_errors */
void agt_commit_complete_cleanup( void ) { if ( initialised ) { agt_cb_commit_complete_set_t* cbSet; while ( !dlq_empty( &callbackQ ) ) { cbSet = ( agt_cb_commit_complete_set_t* )dlq_deque( &callbackQ ); free_callback_set( cbSet ); } initialised = false; } } /* agt_commit_complete_cleanup */
void agt_not_queue_notification_cb_cleanup( void ) { if ( initialised ) { agt_cb_queue_notification_set_t* cbSet; while ( !dlq_empty( &callbackQ ) ) { cbSet = ( agt_cb_queue_notification_set_t* )dlq_deque( &callbackQ ); free_callback_set( cbSet ); } initialised = false; } } /* agt_not_queue_notification_callbacks_cleanup */
/******************************************************************** * FUNCTION ncx_feature_cleanup * * Cleanup the ncx_feature module * * INPUTS: * none * RETURNS: * none *********************************************************************/ void ncx_feature_cleanup (void) { feature_entry_t *feature_entry; if (!feature_init_done) { return; } while (!dlq_empty(&feature_entryQ)) { feature_entry = (feature_entry_t *)dlq_deque(&feature_entryQ); free_feature_entry(feature_entry); } feature_init_done = FALSE; } /* ncx_feature_cleanup */
/******************************************************************** * FUNCTION clean_server_profile * * Clean the server profile variables * * OUTPUTS: * *agt_profile is filled in with params of defaults * *********************************************************************/ static void clean_server_profile (void) { ncx_clean_save_deviationsQ(&agt_profile.agt_savedevQ); while (!dlq_empty(&agt_profile.agt_commit_testQ)) { agt_cfg_commit_test_t *commit_test = (agt_cfg_commit_test_t *) dlq_deque(&agt_profile.agt_commit_testQ); agt_cfg_free_commit_test(commit_test); } if (agt_profile.agt_startup_txid_file) { m__free(agt_profile.agt_startup_txid_file); agt_profile.agt_startup_txid_file = NULL; } } /* clean_server_profile */
/******************************************************************** * FUNCTION ncx_clean_iffeatureQ * * Clean a Q of malloced ncx_iffeature_t struct * * INPUTS: * iffeatureQ == address of Q to clean * *********************************************************************/ void ncx_clean_iffeatureQ (dlq_hdr_t *iffeatureQ) { ncx_iffeature_t *iff; #ifdef DEBUG if (!iffeatureQ) { SET_ERROR(ERR_INTERNAL_PTR); return; } #endif while (!dlq_empty(iffeatureQ)) { iff = (ncx_iffeature_t *)dlq_deque(iffeatureQ); ncx_free_iffeature(iff); } } /* ncx_clean_iffeatureQ */
/******************************************************************** * FUNCTION rpc_err_clean_errQ * * Clean all the entries from a Q of rpc_err_rec_t * * INPUTS: * errQ == Q of rpc_err_rec_t to clean * RETURNS: * none *********************************************************************/ void rpc_err_clean_errQ (dlq_hdr_t *errQ) { rpc_err_rec_t *err; #ifdef DEBUG if (!errQ) { SET_ERROR(ERR_INTERNAL_PTR); return; } #endif /* clean error queue */ while (!dlq_empty(errQ)) { err = (rpc_err_rec_t *)dlq_deque(errQ); rpc_err_free_record(err); } } /* rpc_err_clean_errQ */
/******************************************************************** * FUNCTION xml_msg_clean_hdr * * Clean all the memory used by the specified xml_msg_hdr_t * but do not free the struct itself * * Do NOT reuse this header without calling xml_msg_init_hdr first!!! * xml_msg_t headers were originally meant to be used * only in other messages, but <hello> messages use the hdr * without a wrapper message * * INPUTS: * msg == xml_msg_hdr_t to clean * RETURNS: * none *********************************************************************/ void xml_msg_clean_hdr (xml_msg_hdr_t *msg) { if (!msg) { return; } /* clean prefix queue */ while (!dlq_empty(&msg->prefixQ)) { xmlns_pmap_t *pmap = (xmlns_pmap_t *)dlq_deque(&msg->prefixQ); xmlns_free_pmap(pmap); } /* clean error queue */ rpc_err_clean_errQ(&msg->errQ); // this step not needed; not sure why it was added! msg->withdef = NCX_DEF_WITHDEF; } /* xml_msg_clean_hdr */
/******************************************************************** * FUNCTION yangapi_free_rcb * * Free a YANGAPI control block * * INPUTS: * rcb == Yuma REST-API control block to free * RETURNS: * none *********************************************************************/ void yangapi_free_rcb (yangapi_cb_t *rcb) { if (rcb == NULL) { return; } while (!dlq_empty(&rcb->paramQ)) { yangapi_param_t *param = (yangapi_param_t *)dlq_deque(&rcb->paramQ); if (param) { yangapi_free_param(param); } } yangapi_clean_keyvalQ(rcb); m__free(rcb->accept); m__free(rcb->request_method); m__free(rcb->request_uri); xpath_free_pcb(rcb->request_xpath); xpath_free_result(rcb->request_xpath_result); xpath_free_pcb(rcb->query_select_xpath); xpath_free_result(rcb->query_select_xpath_result); xpath_free_pcb(rcb->query_test_xpath); xpath_free_result(rcb->query_test_xpath_result); m__free(rcb->content_type); m__free(rcb->content_length); m__free(rcb->if_modified_since); m__free(rcb->if_unmodified_since); m__free(rcb->if_match); m__free(rcb->if_none_match); m__free(rcb); } /* yangapi_free_rcb */
/******************************************************************** * FUNCTION agt_ses_request_close * * Start the close of the specified session * * INPUTS: * sid == session ID to close * killedby == session ID executing the kill-session or close-session * termreason == termination reason code * * RETURNS: * none *********************************************************************/ void agt_ses_request_close (ses_cb_t *scb, ses_id_t killedby, ses_term_reason_t termreason) { if (!scb) { return; } /* N/A for dummy sessions */ if (scb->type==SES_TYP_DUMMY) { return; } scb->killedbysid = killedby; scb->termreason = termreason; /* change the session control block state */ switch (scb->state) { case SES_ST_IDLE: case SES_ST_SHUTDOWN: case SES_ST_SHUTDOWN_REQ: agt_ses_kill_session(scb, killedby, termreason); break; case SES_ST_IN_MSG: scb->state = SES_ST_SHUTDOWN_REQ; break; default: if (dlq_empty(&scb->outQ)) { agt_ses_kill_session(scb, killedby, termreason); } else { scb->state = SES_ST_SHUTDOWN_REQ; } } } /* agt_ses_request_close */
/******************************************************************** * FUNCTION clean_undorec * * Clean all the memory used by the specified agt_cfg_undo_rec_t * but do not free the struct itself * * !!! The caller must free internal pointers that were malloced * !!! instead of copied. This function does not check them!!! * * INPUTS: * undo == agt_cfg_undo_rec_t to clean * reuse == TRUE if possible reuse * FALSE if this node is being freed right now * * RETURNS: * none *********************************************************************/ static void clean_undorec (agt_cfg_undo_rec_t *undo, boolean reuse) { if (undo->free_curnode && undo->curnode) { val_free_value(undo->curnode); } if (undo->curnode_clone) { val_free_value(undo->curnode_clone); } if (undo->newnode_marker) { val_free_value(undo->newnode_marker); } if (undo->curnode_marker) { val_free_value(undo->curnode_marker); } /* really expecting the extra_deleteQ to be empty at this point */ while (!dlq_empty(&undo->extra_deleteQ)) { agt_cfg_nodeptr_t *nodeptr = (agt_cfg_nodeptr_t *) dlq_deque(&undo->extra_deleteQ); if (nodeptr && nodeptr->node) { val_remove_child(nodeptr->node); val_free_value(nodeptr->node); } else { SET_ERROR(ERR_INTERNAL_VAL); } agt_cfg_free_nodeptr(nodeptr); } if (reuse) { agt_cfg_init_undorec(undo); } } /* clean_undorec */
/******************************************************************** * FUNCTION exit_config_mode * * Exit the configuration mode * * INPUTS: * session_cb == session control block to use * *********************************************************************/ static void exit_config_mode (session_cb_t *session_cb) { session_cb->config_mode = FALSE; session_cb->config_no_active = FALSE; session_cb->config_edit_dirty = FALSE; session_cb->alt_names = session_cb->config_alt_names; session_cb->match_names = session_cb->config_match_names; m__free(session_cb->config_path); session_cb->config_path = NULL; session_cb->config_curval = NULL; session_cb->config_curobj = NULL; session_cb->config_curkey = NULL; val_free_value(session_cb->config_etree); session_cb->config_etree = NULL; session_cb->config_ecurval = NULL; while (!dlq_empty(&session_cb->config_editQ)) { config_edit_t *edit = (config_edit_t *) dlq_deque(&session_cb->config_editQ); free_config_edit(edit); } } /* exit_config_mode */
/******************************************************************** * FUNCTION handle_config_input * (config mode input received) * * e.g., * nacm * interface eth0 * interface eth0 mtu 1500 * * INPUTS: * server_cb == server control block to use * session_cb == session control block to use * line == CLI input in progress; this line is passed to the * tk_parse functions which expects non-const ptr * * RETURNS: * status *********************************************************************/ status_t handle_config_input (server_cb_t *server_cb, session_cb_t *session_cb, xmlChar *line) { if (LOGDEBUG2) { log_debug2("\nconfig mode input for line '%s'\n", line); } /* get a token chain and parse the line of input into tokens */ tk_chain_t *tkc = tk_new_chain(); if (tkc == NULL) { log_error("\nError: could not malloc token chain\n"); return ERR_INTERNAL_MEM; } tk_setup_chain_cli(tkc, line); status_t res = tk_tokenize_input(tkc, NULL); if (res != NO_ERR) { tk_free_chain(tkc); return res; } /* check the number of tokens parsed */ uint32 tkcount = tk_token_count(tkc); if (LOGDEBUG2) { log_debug2("\nconfig token count: %u", tkcount); } if (tkcount == 0) { tk_free_chain(tkc); return NO_ERR; } obj_template_t *startobj = session_cb->config_curobj; val_value_t *startval = session_cb->config_curval; val_value_t *startroot = session_cb->config_etree; val_value_t *starteval = session_cb->config_ecurval; session_cb->config_no_active = FALSE; session_cb->config_estartval = starteval; session_cb->config_firstnew = NULL; boolean gotleafys = FALSE; boolean gotexit = FALSE; boolean gotapply = FALSE; boolean gotdo = FALSE; boolean done = FALSE; while (!done && res == NO_ERR) { /* parse nodes and possibly keys until a value node or the end * of the token chain is reached */ res = parse_node(tkc, session_cb, &done, &gotexit, &gotapply, &gotdo); obj_template_t *obj = session_cb->config_curobj; if (res == NO_ERR && done && !gotdo && !gotexit && !gotapply && obj && obj_is_leafy(obj)) { /* get the next node as a value node */ res = parse_value(session_cb, tkc); gotleafys = TRUE; if (tk_next_typ(tkc) != TK_TT_NONE) { res = ERR_NCX_EXTRA_NODE; log_error("\nError: unexpected input at end of line\n"); } if (res == NO_ERR && !session_cb->config_no_active) { if (obj->parent && !obj_is_root(obj->parent)) { session_cb->config_curobj = obj->parent; } else { session_cb->config_curobj = NULL; } /* reset to parent of the leaf just parsed */ session_cb->config_ecurval = session_cb->config_ecurval->parent; } } } /* check exit conditions */ if (res != NO_ERR || done || gotexit || gotapply || gotdo) { if (res == NO_ERR && gotexit) { res = process_exit(server_cb, session_cb); if (res == NO_ERR) { res = set_config_path(session_cb); } } else if (res == NO_ERR && gotapply) { if (session_cb->config_curobj && dlq_empty(&session_cb->config_editQ) && session_cb->config_edit_mode != CFG_EDITMODE_LINE) { /* add an edit just because the user entered a * sub-mode and then invoked apply */ res = add_edit(session_cb); } clear_current_level(session_cb); if (res == NO_ERR) { res = process_apply(server_cb, session_cb); } } else if (res == NO_ERR && gotdo) { res = process_do_command(server_cb, session_cb, tkc, line); } else if (res == NO_ERR && done) { res = process_line_done(server_cb, session_cb, startobj, gotleafys); if (res == NO_ERR && session_cb->config_curobj && session_cb->config_curobj != startobj) { res = set_config_path(session_cb); } } if (res != NO_ERR) { /* reset current node pointers */ session_cb->config_curobj = startobj; session_cb->config_curval = startval; if (startroot == NULL) { val_free_value(session_cb->config_etree); session_cb->config_etree = NULL; session_cb->config_ecurval = NULL; session_cb->config_firstnew = NULL; } else { if (session_cb->config_firstnew) { if (session_cb->config_firstnew->parent) { val_remove_child(session_cb->config_firstnew); } val_free_value(session_cb->config_firstnew); session_cb->config_firstnew = NULL; } session_cb->config_etree = startroot; session_cb->config_ecurval = starteval; } (void)set_config_path(session_cb); } } tk_free_chain(tkc); return res; } /* handle_config_input */
/******************************************************************** * FUNCTION process_apply * (config mode input received) * Handle the apply command and check if there are edits * to apply to the server. If so apply the edits. * * INPUTS: * server_cb == server control block to use * session_cb == session control block to use * * RETURNS: * status *********************************************************************/ static status_t process_apply (server_cb_t *server_cb, session_cb_t *session_cb) { if (dlq_empty(&session_cb->config_editQ)) { if (LOGDEBUG2) { log_debug2("\nSkipping apply, no edits"); } session_cb->config_edit_dirty = FALSE; return NO_ERR; } /* make a dummy config root -- it will not be used; only the child * nodes added to this container will be added to the <config> * parameter in the <edit-config> operation */ val_value_t *configval = xml_val_new_root(NCX_EL_CONFIG, xmlns_nc_id()); if (configval == NULL) { log_error("\nError: malloc failed"); return ERR_INTERNAL_MEM; } status_t res = NO_ERR; boolean anyedits = FALSE; uint32 editcnt = dlq_count(&session_cb->config_editQ); while (!dlq_empty(&session_cb->config_editQ)) { config_edit_t *edit = (config_edit_t *) dlq_deque(&session_cb->config_editQ); /* compare the edit to the shadow config to see if it * represents any change or not */ boolean ischange = check_edit(session_cb, edit); if (ischange) { /** TBD: add to tree and collapse all edits!!! */ val_add_child(edit->edit_payload, configval); edit->edit_payload = NULL; anyedits = TRUE; } else if (LOGDEBUG3) { log_debug3("\nSkipping edit due to no change:\n"); val_dump_value(edit->edit_payload, 0); } free_config_edit(edit); } if (!anyedits) { val_free_value(configval); return NO_ERR; } if (server_cb->program_mode == PROG_MODE_SERVER) { if (LOGDEBUG) { if (editcnt == 1) { log_debug("\nApplying 1 edit\n"); } else { log_debug("\nApplying %u edits\n", editcnt); } } } else { if (LOGINFO) { const xmlChar *sesname = (session_cb->session_cfg) ? session_cb->session_cfg->name : NCX_EL_DEFAULT; if (editcnt == 1) { log_info("\nApplying 1 edit to session '%s'\n", sesname); } else { log_info("\nApplying %u edits to session '%s'\n", editcnt, sesname); } } } session_cb->command_mode = CMD_MODE_CONF_APPLY; session_cb->config_edit_dirty = FALSE; res = send_edit_config_to_server(server_cb, session_cb, NULL, configval, TRUE, session_cb->timeout, OP_DEFOP_MERGE); /* configval consumed no matter what! */ return res; } /* process_apply */
/******************************************************************** * FUNCTION do_aliases (local RPC) * * aliases * aliases clear * aliases show * aliases load[=filespec] * aliases save[=filespec] * * Handle the aliases command, based on the parameter * * INPUTS: * server_cb == server control block to use * rpc == RPC method for the aliases command * line == CLI input in progress * len == offset into line buffer to start parsing * * RETURNS: * status *********************************************************************/ status_t do_aliases (server_cb_t *server_cb, obj_template_t *rpc, const xmlChar *line, uint32 len) { val_value_t *valset; status_t res = NO_ERR; valset = get_valset(server_cb, rpc, &line[len], &res); if (res == NO_ERR && valset) { /* get the 1 of N 'alias-action' choice */ val_value_t *parm; const xmlChar *parmval = NULL; boolean done = FALSE; /* aliases show */ parm = val_find_child(valset, YANGCLI_MOD, YANGCLI_SHOW); if (parm) { show_aliases(); done = TRUE; } /* aliases clear */ if (!done) { parm = val_find_child(valset, YANGCLI_MOD, YANGCLI_CLEAR); if (parm) { dlq_hdr_t *aliasQ = get_aliasQ(); if (!dlq_empty(aliasQ)) { free_aliases(); log_info("\nDeleted all aliases from memory\n"); update_yangcli_param_change_flag (ALIASES_FILE, TRUE); }else { log_info("\nNo aliases found\n"); } done = TRUE; } } /* aliases load */ if (!done) { parm = val_find_child(valset, YANGCLI_MOD, YANGCLI_LOAD); if (parm) { if (xml_strlen(VAL_STR(parm))) { parmval = VAL_STR(parm); } else { parmval = get_aliases_file(); } res = load_aliases(parmval, !val_set_by_default(parm)); if (res == NO_ERR) { log_info("\nLoaded aliases OK from '%s'\n", parmval); } else { log_error("\nLoad aliases from '%s' failed (%s)\n", parmval, get_error_string(res)); } done = TRUE; } } /* aliases save */ if (!done) { parm = val_find_child(valset, YANGCLI_MOD, YANGCLI_SAVE); if (parm) { if (xml_strlen(VAL_STR(parm))) { parmval = VAL_STR(parm); } else { parmval = get_aliases_file(); } res = save_aliases(parmval); if (res == NO_ERR) { log_info("\nSaved aliases OK to '%s'\n", parmval); } else if (res != ERR_NCX_CANCELED) { log_error("\nSave aliases to '%s' failed (%s)\n", parmval, get_error_string(res)); } done = TRUE; } } if (!done) { /* no parameters; show all aliases */ show_aliases(); } } if (valset) { val_free_value(valset); } return res; } /* do_aliases */
/******************************************************************** * FUNCTION load_running_config * * Load the NV startup config into the running config * * INPUTS: * startup == startup filespec provided by the user * == NULL if not set by user * (use default name and specified search path instead) * loaded == address of return config loaded flag * * OUTPUTS: * *loaded == TRUE if some config file was loaded * * The <running> config is loaded from NV-storage, * if the NV-storage <startup> config can be found an read * RETURNS: * status *********************************************************************/ static status_t load_running_config (const xmlChar *startup, boolean *loaded) { cfg_template_t *cfg; xmlChar *fname; agt_profile_t *profile; status_t res; res = NO_ERR; *loaded = FALSE; profile = agt_get_profile(); cfg = cfg_get_config(NCX_CFG_RUNNING); if (!cfg) { log_error("\nagt: No running config found!!"); return SET_ERROR(ERR_INTERNAL_VAL); } /* use the user-set startup or default filename */ if (startup) { /* relative filespec, use search path */ fname = ncxmod_find_data_file(startup, FALSE, &res); } else { /* search for the default startup-cfg.xml filename */ fname = ncxmod_find_data_file(NCX_DEF_STARTUP_FILE, FALSE, &res); } /* check if error finding the filespec */ if (!fname) { if (startup) { if (res == NO_ERR) { res = ERR_NCX_MISSING_FILE; } log_error("\nError: Startup config file (%s) not found (%s).", startup, get_error_string(res)); return res; } else { log_info("\nDefault startup config file (%s) not found." "\n Booting with default running configuration!\n", NCX_DEF_STARTUP_FILE); return NO_ERR; } } else if (LOGDEBUG2) { log_debug2("\nFound startup config: '%s'", fname); } /* try to load the config file that was found or given */ res = agt_ncx_cfg_load(cfg, CFG_LOC_FILE, fname); if (res == ERR_XML_READER_START_FAILED) { log_error("\nagt: Error: Could not open startup config file" "\n (%s)\n", fname); } else if (res != NO_ERR) { /* if an error is returned then it was a hard error * since the startup_error and running_error profile * variables have already been accounted for. * An error in the setup or in the AGT_RPC_PH_INVOKE phase * of the <load-config> operation occurred */ log_error("\nError: load startup config failed (%s)", get_error_string(res)); if (!dlq_empty(&cfg->load_errQ)) { *loaded = TRUE; } } else { /* assume OK or startup and running continue; if 1 or both is not * set then the server will exit anyway and the config state * will not matter */ profile->agt_config_state = AGT_CFG_STATE_OK; *loaded = TRUE; boolean errdone = FALSE; boolean errcontinue = FALSE; if (profile->agt_load_validate_errors) { if (profile->agt_startup_error) { /* quit if any startup validation errors */ log_error("\nError: validation errors occurred loading the " "<running> database\n from NV-storage" " (%s)\n", fname); errdone = TRUE; } else { /* continue if any startup errors */ log_warn("\nWarning: validation errors occurred loading " "the <running> database\n from NV-storage" " (%s)\n", fname); errcontinue = TRUE; } } if (!errdone && profile->agt_load_rootcheck_errors) { if (profile->agt_startup_error) { /* quit if any startup root-check validation errors */ log_error("\nError: root-check validation errors " "occurred loading the <running> database\n" " from NV-storage (%s)\n", fname); errdone = TRUE; } else { /* continue if any root-check validation errors */ log_warn("\nWarning: root-check validation errors " "occurred loading the <running> database\n" " from NV-storage (%s)\n", fname); errcontinue = TRUE; } } if (!errdone && profile->agt_load_top_rootcheck_errors) { if (profile->agt_running_error) { /* quit if any top-level root-check validation errors */ log_error("\nError: top-node root-check validation errors " "occurred loading the <running> database\n" " from NV-storage (%s)\n", fname); errdone = TRUE; } else { /* continue if any startup errors */ log_warn("\nWarning: top-node root-check validation errors " "occurred loading the <running> database\n" " from NV-storage (%s)\n", fname); profile->agt_config_state = AGT_CFG_STATE_BAD; errcontinue = TRUE; } } if (!errdone && profile->agt_load_apply_errors) { /* quit if any apply-to-running SIL errors */ errdone = TRUE; log_error("\nError: fatal errors " "occurred loading the <running> database " "from NV-storage\n (%s)\n", fname); } if (errdone) { res = ERR_NCX_OPERATION_FAILED; } else if (errcontinue) { val_purge_errors_from_root(cfg->root); log_info("\nagt: Startup config loaded after pruning error nodes\n" "Source: %s\n", fname); } else { log_info("\nagt: Startup config loaded OK\n Source: %s\n", fname); } } if (LOGDEBUG) { log_debug("\nContents of %s configuration:", cfg->name); val_dump_value(cfg->root, 0); log_debug("\n"); } if (fname) { m__free(fname); } return res; } /* load_running_config */
/******************************************************************** * FUNCTION y_ietf_netconf_partial_lock_partial_lock_invoke * * RPC invocation phase * All constraints have passed at this point. * Call device instrumentation code in this function. * * INPUTS: * see agt/agt_rpc.h for details * * RETURNS: * error status ********************************************************************/ static status_t y_ietf_netconf_partial_lock_partial_lock_invoke ( ses_cb_t *scb, rpc_msg_t *msg, xml_node_t *methnode) { plock_cb_t *plcb; val_value_t *testval, *newval; xpath_result_t *result; xpath_resnode_t *resnode, *clearnode; xmlChar *pathbuff; cfg_template_t *running; status_t res; ncx_num_t num; res = NO_ERR; plcb = (plock_cb_t *)msg->rpc_user1; result = plock_get_final_result(plcb); running = cfg_get_config_id(NCX_CFGID_RUNNING); /* try to lock all the target nodes */ for (resnode = xpath_get_first_resnode(result); resnode != NULL && res == NO_ERR; resnode = xpath_get_next_resnode(resnode)) { testval = xpath_get_resnode_valptr(resnode); res = val_set_partial_lock(testval, plcb); if (res != NO_ERR) { agt_record_error(scb, &msg->mhdr, NCX_LAYER_OPERATION, res, methnode, NCX_NT_NONE, NULL, NCX_NT_VAL, testval); } } /* unlock any nodes already attempted if any fail */ if (res != NO_ERR) { for (clearnode = xpath_get_first_resnode(result); clearnode != NULL; clearnode = xpath_get_next_resnode(clearnode)) { testval = xpath_get_resnode_valptr(clearnode); val_clear_partial_lock(testval, plcb); if (clearnode == resnode) { return res; } } return res; } /* add this partial lock to the running config */ res = cfg_add_partial_lock(running, plcb); if (res != NO_ERR) { /* should not happen since config lock state could * not have changed since validate callback */ agt_record_error(scb, &msg->mhdr, NCX_LAYER_OPERATION, res, methnode, NCX_NT_NONE, NULL, NCX_NT_NONE, NULL); for (clearnode = xpath_get_first_resnode(result); clearnode != NULL; clearnode = xpath_get_next_resnode(clearnode)) { testval = xpath_get_resnode_valptr(clearnode); val_clear_partial_lock(testval, plcb); } plock_cb_free(plcb); return res; } /* setup return data only if lock successful * cache the reply instead of stream the reply * in case there is any error; if so; the partial * lock will be backed out and the dataQ cleaned * for an error exit; add lock-id leaf first */ msg->rpc_data_type = RPC_DATA_YANG; ncx_init_num(&num); num.u = plock_get_id(plcb); newval = xml_val_new_number (y_ietf_netconf_partial_lock_N_lock_id, val_get_nsid(msg->rpc_input), &num, NCX_BT_UINT32); ncx_clean_num(NCX_BT_UINT32, &num); if (newval == NULL) { res = ERR_INTERNAL_MEM; agt_record_error(scb, &msg->mhdr, NCX_LAYER_OPERATION, res, methnode, NCX_NT_NONE, NULL, NCX_NT_NONE, NULL); } else { dlq_enque(newval, &msg->rpc_dataQ); } /* add lock-node leaf-list instance for each resnode */ for (resnode = xpath_get_first_resnode(result); resnode != NULL && res == NO_ERR; resnode = xpath_get_next_resnode(resnode)) { /* Q&D method: generate the i-i string as a plain * string and add any needed prefixes to the global * prefix map for the reply message (in mhdr) */ pathbuff = NULL; testval = xpath_get_resnode_valptr(resnode); res = val_gen_instance_id(&msg->mhdr, testval, NCX_IFMT_XPATH1, &pathbuff); if (res == NO_ERR) { /* make leaf; pass off pathbuff malloced memory */ newval = xml_val_new_string (y_ietf_netconf_partial_lock_N_locked_node, val_get_nsid(msg->rpc_input), pathbuff); if (newval == NULL) { res = ERR_INTERNAL_MEM; m__free(pathbuff); pathbuff = NULL; } } if (res == NO_ERR) { dlq_enque(newval, &msg->rpc_dataQ); } else { agt_record_error(scb, &msg->mhdr, NCX_LAYER_OPERATION, res, methnode, NCX_NT_NONE, NULL, NCX_NT_NONE, NULL); } } if (res != NO_ERR) { /* back out everything, except waste the lock ID */ for (clearnode = xpath_get_first_resnode(result); clearnode != NULL; clearnode = xpath_get_next_resnode(clearnode)) { testval = xpath_get_resnode_valptr(clearnode); val_clear_partial_lock(testval, plcb); } cfg_delete_partial_lock(running, plock_get_id(plcb)); /* clear any data already queued */ while (!dlq_empty(&msg->rpc_dataQ)) { testval = (val_value_t *) dlq_deque(&msg->rpc_dataQ); val_free_value(testval); } msg->rpc_data_type = RPC_DATA_NONE; } return res; } /* y_ietf_netconf_partial_lock_partial_lock_invoke */