/******************************************************************** * FUNCTION clear_one_level * Clear the current level for the ecurptr * The exit command was given so backing up top the * parent of the config_ecurptr * * INPUTS: * session_cb == session control block to use *********************************************************************/ static void clear_one_level (session_cb_t *session_cb) { val_value_t *target = session_cb->config_ecurval; if (target == NULL) { return; } val_value_t *parent = target->parent; if (session_cb->config_estartval == target) { session_cb->config_estartval = NULL; } if (parent) { val_remove_child(target); } val_free_value(target); session_cb->config_ecurval = parent; if (parent == NULL) { session_cb->config_etree = NULL; session_cb->config_estartval = NULL; } } /* clear_one_level */
/******************************************************************** * FUNCTION clear_current_level * Clear the current level without changing it * * INPUTS: * session_cb == session control block to use *********************************************************************/ static void clear_current_level (session_cb_t *session_cb) { val_value_t *target = session_cb->config_ecurval; if (target == NULL) { return; } if (session_cb->config_estartval == NULL) { /* clear everything out */ val_free_value(session_cb->config_etree); session_cb->config_etree = NULL; session_cb->config_ecurval = NULL; return; } boolean islist = obj_is_list(target->obj); val_value_t *chval = val_get_first_child(target); val_value_t *nextval = NULL; for (; chval; chval = nextval) { nextval = val_get_next_child(chval); if (islist && obj_is_key(chval->obj)) { continue; } val_remove_child(chval); val_free_value(chval); } } /* clear_current_level */
/******************************************************************** * 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 do_while (local RPC) * * Handle the while command; start a new loopcb context * * while expr='xpath-str' [docroot=$foo] * * INPUTS: * server_cb == server control block to use * rpc == RPC method for the show command * line == CLI input in progress * len == offset into line buffer to start parsing * * RETURNS: * status *********************************************************************/ status_t do_while (server_cb_t *server_cb, obj_template_t *rpc, const xmlChar *line, uint32 len) { val_value_t *valset, *docroot, *expr, *dummydoc, *maxloops; xpath_pcb_t *pcb; status_t res; uint32 maxloopsval; docroot = NULL; expr = NULL; pcb = NULL; dummydoc = NULL; res = NO_ERR; maxloopsval = YANGCLI_DEF_MAXLOOPS; valset = get_valset(server_cb, rpc, &line[len], &res); if (valset == NULL) { return res; } if (res != NO_ERR) { val_free_value(valset); return res; } if (valset->res != NO_ERR) { res = valset->res; val_free_value(valset); return res; } /* get the expr parameter */ expr = val_find_child(valset, YANGCLI_MOD, YANGCLI_EXPR); if (expr == NULL) { res = ERR_NCX_MISSING_PARM; } else if (expr->res != NO_ERR) { res = expr->res; } if (res == NO_ERR) { /* get the optional docroot parameter */ docroot = val_find_child(valset, YANGCLI_MOD, YANGCLI_DOCROOT); if (docroot != NULL) { if (docroot->res != NO_ERR) { res = docroot->res; } else { val_remove_child(docroot); } } } if (res == NO_ERR && docroot == NULL) { dummydoc = xml_val_new_struct(NCX_EL_DATA, xmlns_nc_id()); if (dummydoc == NULL) { res = ERR_INTERNAL_MEM; } else { docroot = dummydoc; } } if (res == NO_ERR) { /* get the optional maxloops parameter */ maxloops = val_find_child(valset, YANGCLI_MOD, YANGCLI_MAXLOOPS); if (maxloops != NULL) { if (maxloops->res != NO_ERR) { res = maxloops->res; } else { maxloopsval = VAL_UINT(maxloops); } } } if (res == NO_ERR) { /* got all the parameters, and setup the XPath control block */ pcb = xpath_new_pcb_ex(VAL_STR(expr), xpath_getvar_fn, server_cb->runstack_context); if (pcb == NULL) { res = ERR_INTERNAL_MEM; } else { /* save these parameter and start a new while context block */ res = runstack_handle_while(server_cb->runstack_context, maxloopsval, pcb, /* hand off memory here */ docroot); /* hand off memory here */ if (res == NO_ERR) { /* hand off the pcb and docroot memory above */ pcb = NULL; docroot = NULL; } } } /* cleanup and exit */ if (valset) { val_free_value(valset); } if (pcb) { xpath_free_pcb(pcb); } if (docroot) { val_free_value(docroot); } return res; } /* do_while */
/******************************************************************** * 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 */