/******************************************************************** * FUNCTION add_alias * * Add the alias record * * INPUTS: * alias == alias to add * * RETURNS: * status *********************************************************************/ static status_t add_alias (alias_cb_t *alias) { dlq_hdr_t *aliasQ = get_aliasQ(); alias_cb_t *curalias; int ret; if (aliasQ == NULL) { SET_ERROR(ERR_INTERNAL_VAL); free_alias(alias); return ERR_INTERNAL_VAL; } for (curalias = (alias_cb_t *)dlq_firstEntry(aliasQ); curalias != NULL; curalias = (alias_cb_t *)dlq_nextEntry(curalias)) { ret = xml_strcmp(curalias->name, alias->name); if (ret == 0) { SET_ERROR(ERR_NCX_DUP_ENTRY); free_alias(alias); return ERR_NCX_DUP_ENTRY; } else if (ret > 0) { dlq_insertAhead(alias, curalias); return NO_ERR; } } /* new last entry */ dlq_enque(alias, aliasQ); return NO_ERR; } /* add_alias */
/******************************************************************** * FUNCTION y_simple_list_test_get_counter_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_simple_list_test_get_counter_invoke ( ses_cb_t *scb, rpc_msg_t *msg, xml_node_t *methnode) { status_t res = NO_ERR; val_value_t *countVal; xmlChar countBuff[100]; /* remove the next line if scb is used */ (void)scb; /* remove the next line if msg is used */ (void)msg; /* remove the next line if methnode is used */ (void)methnode; /* invoke your device instrumentation code here */ snprintf((char *)countBuff, sizeof(countBuff), "%u", count_static); countVal = val_make_string(0, (xmlChar*)"count", countBuff); if (countVal == NULL) { val_free_value(countVal); return ERR_INTERNAL_MEM; } dlq_enque(countVal, &msg->rpc_dataQ); msg->rpc_data_type = RPC_DATA_STD; return res; } /* y_simple_list_test_get_counter_invoke */
/******************************************************************** * FUNCTION get_my_session_invoke * * get-my-session : invoke params callback * * INPUTS: * see rpc/agt_rpc.h * RETURNS: * status *********************************************************************/ static status_t get_my_session_invoke (ses_cb_t *scb, rpc_msg_t *msg, xml_node_t *methnode) { val_value_t *indentval, *linesizeval, *withdefval; xmlChar numbuff[NCX_MAX_NUMLEN]; (void)methnode; snprintf((char *)numbuff, sizeof(numbuff), "%u", scb->indent); indentval = val_make_string(mysesmod->nsid, NCX_EL_INDENT, numbuff); if (indentval == NULL) { return ERR_INTERNAL_MEM; } snprintf((char *)numbuff, sizeof(numbuff), "%u", scb->linesize); linesizeval = val_make_string(mysesmod->nsid, NCX_EL_LINESIZE, numbuff); if (linesizeval == NULL) { val_free_value(indentval); return ERR_INTERNAL_MEM; } withdefval = val_make_string(mysesmod->nsid, NCX_EL_WITH_DEFAULTS, ncx_get_withdefaults_string(scb->withdef)); if (withdefval == NULL) { val_free_value(indentval); val_free_value(linesizeval); return ERR_INTERNAL_MEM; } dlq_enque(indentval, &msg->rpc_dataQ); dlq_enque(linesizeval, &msg->rpc_dataQ); dlq_enque(withdefval, &msg->rpc_dataQ); msg->rpc_data_type = RPC_DATA_YANG; return NO_ERR; } /* get_my_session_invoke */
/******************************************************************** * FUNCTION add_request * * Add an RPC request to the Q * * INPUTS: * scb == session control block * req == mgr_rpc_req_t to add * * RETURNS: * none *********************************************************************/ static void add_request (ses_cb_t *scb, mgr_rpc_req_t *req) { mgr_scb_t *mscb; mscb = mgr_ses_get_mscb(scb); (void)uptime(&req->starttime); dlq_enque(req, &mscb->reqQ); } /* add_request */
/******************************************************************** * FUNCTION ncx_set_feature_code_entry * * Create or set a feature_entry struct for the specified * feature code parameter * * !!! THIS FUNCTION IS DEPRECATED!!! * !!! The --feature-code and --feature-code-default parameters are ignored * !!! Feature code generation is not controlled by this parameter * * INPUTS: * featstr == feature parameter string * featcode == ncx_feature_code_t enumeration to set * * RETURNS: * status *********************************************************************/ status_t ncx_set_feature_code_entry (const xmlChar *featstr, ncx_feature_code_t featcode) { feature_entry_t *fentry; status_t res; uint32 cnt; #ifdef DEBUG if (featstr == NULL) { return SET_ERROR(ERR_INTERNAL_PTR); } #endif res = NO_ERR; fentry = find_feature_entry(featstr, &feature_entryQ); if (fentry != NULL) { if (fentry->code_set) { if (fentry->code != featcode) { log_error("\nError: feature '%s' already set with " "conflicting value", featstr); res = ERR_NCX_INVALID_VALUE; } else { log_info("\nFeature '%s' already set with " "same value", featstr); } } else { fentry->code_set = TRUE; fentry->code = featcode; } } else { cnt = 0; res = split_feature_string(featstr, &cnt); if (res == NO_ERR) { fentry = new_feature_entry(featstr); if (fentry == NULL) { res = ERR_INTERNAL_MEM; } else { fentry->code_set = TRUE; fentry->code = featcode; dlq_enque(fentry, &feature_entryQ); } } } return res; } /* ncx_set_feature_code_entry */
/******************************************************************** * FUNCTION add_pmap * * Add a prefix mapping entry * * INPUTS: * msg == message to search * newpmap == xmlns_pmap_t struct to add * * RETURNS: * none *********************************************************************/ static void add_pmap (xml_msg_hdr_t *msg, xmlns_pmap_t *newpmap) { xmlns_pmap_t *pmap; /* add the new prefix mapping */ for (pmap = (xmlns_pmap_t *)dlq_firstEntry(&msg->prefixQ); pmap != NULL; pmap = (xmlns_pmap_t *)dlq_nextEntry(pmap)) { if (newpmap->nm_id < pmap->nm_id) { dlq_insertAhead(newpmap, pmap); return; } } dlq_enque(newpmap, &msg->prefixQ); } /* add_pmap */
/******************************************************************** * FUNCTION ncx_set_feature_enable * * Create or set a feature_entry struct for the specified * feature enabled parameter * * Called from SIL init code * * INPUTS: * modname == name of module defining the feature * name == feature name * flag == feature enabled flag * * RETURNS: * status *********************************************************************/ status_t ncx_set_feature_enable (const xmlChar *modname, const xmlChar *name, boolean flag) { assert( modname && "modname is NULL!" ); assert( name && "modname is NULL!" ); status_t res = NO_ERR; feature_entry_t *fentry = find_feature_entry2(modname, name, &feature_entryQ); if (fentry != NULL) { if (fentry->enable_set) { if (fentry->enable != flag) { if (flag) { /* SIL enabled, so previous CLI disable is allowed */ log_debug("\nFeature '%s' already disabled from CLI, " "ignoring SIL disable", name); } else { /* SIL disabled so override CLI enable */ log_info("\nFeature '%s' disabled in SIL, " "overriding CLI enable", name); fentry->enable = FALSE; } } /* else same value so ignore */ } else { fentry->enable_set = TRUE; fentry->enable = flag; } } else { fentry = new_feature_entry2(modname, name); if (fentry == NULL) { res = ERR_INTERNAL_MEM; } else { fentry->enable_set = TRUE; fentry->enable = flag; dlq_enque(fentry, &feature_entryQ); } } return res; } /* ncx_set_feature_enable */
status_t agt_not_queue_notification_cb_register( const xmlChar *modname, agt_not_queue_notification_cb_t cb ) { assert( modname ); agt_cb_queue_notification_set_t* cbSet = find_callback_set( modname ); if ( !cbSet ) { cbSet = new_callback_set( modname ); if ( !cbSet ) { return ERR_INTERNAL_MEM; } dlq_enque( cbSet, &callbackQ ); } cbSet->callback = cb; return NO_ERR; }
/******************************************************************** * FUNCTION add_edit * (config mode input received) * Add an edit to the server config_editQ * * INPUTS: * session_cb == session control block to use * * RETURNS: * status *********************************************************************/ static status_t add_edit (session_cb_t *session_cb) { if (session_cb->config_etree) { op_editop_t delop = get_del_op(session_cb); op_editop_t op = (session_cb->config_no_active) ? delop : OP_EDITOP_MERGE; val_value_t *clone = val_clone(session_cb->config_etree); if (clone == NULL) { return ERR_INTERNAL_MEM; } config_edit_t *edit = new_config_edit(op, clone); if (edit == NULL) { val_free_value(clone); return ERR_INTERNAL_MEM; } session_cb->config_edit_dirty = TRUE; dlq_enque(edit, &session_cb->config_editQ); } return NO_ERR; } /* add_edit */
/******************************************************************** * FUNCTION insert_event_cb * * Insert a new event control block * * INPUTS: * newcb == control block to insert *********************************************************************/ static void insert_event_cb (event_cb_t *newcb) { /* insert sorted by module-name, event-name */ event_cb_t *cb = (event_cb_t *)dlq_firstEntry(&event_cbQ); for (; cb; cb = (event_cb_t *)dlq_nextEntry(cb)) { int ret = xml_strcmp(newcb->modname, cb->modname); if (ret < 0) { dlq_insertAhead(newcb, cb); return; } else if (ret == 0) { int ret2 = xml_strcmp(newcb->event, cb->event); if (ret2 <= 0) { dlq_insertAhead(newcb, cb); return; } } } /* new last entry */ dlq_enque(newcb, &event_cbQ); } /* insert_event_cb */
/******************************************************************** * FUNCTION ncx_set_feature_enable_entry * * Create or set a feature_entry struct for the specified * feature enabled parameter * * Called from CLI/conf handler code * * INPUTS: * featstr == feature parameter string * flag == enabled flag * * RETURNS: * status *********************************************************************/ status_t ncx_set_feature_enable_entry (const xmlChar *featstr, boolean flag) { #ifdef DEBUG if (featstr == NULL) { return SET_ERROR(ERR_INTERNAL_PTR); } #endif status_t res = NO_ERR; feature_entry_t *fentry = find_feature_entry(featstr, &feature_entryQ); if (fentry != NULL) { if (fentry->enable_set) { if (fentry->enable != flag) { log_info("\nFeature '%s' already %s so ignoring new value", (flag) ? "disabled" : "enabled", featstr); res = ERR_NCX_INVALID_VALUE; } } else { fentry->enable_set = TRUE; fentry->enable = flag; } } else { fentry = new_feature_entry(featstr); if (fentry == NULL) { res = ERR_INTERNAL_MEM; } else { fentry->enable_set = TRUE; fentry->enable = flag; dlq_enque(fentry, &feature_entryQ); } } return res; } /* ncx_set_feature_enable_entry */
/******************************************************************** * FUNCTION y_starter_starter_get_load_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_starter_starter_get_load_invoke ( ses_cb_t *scb, rpc_msg_t *msg, xml_node_t *methnode) { status_t res = NO_ERR; /* remove the next line if scb is used */ (void)scb; /* remove the next line if msg is used */ (void)msg; /* remove the next line if methnode is used */ (void)methnode; /* invoke your device instrumentation code here */ /*********************** THIS PART IS ADDED MANUALLY BY LEVI *************************/ //--------- GET LOAD DATA ---------------- //it looks like this: "0.01 0.14 0.12 1/309 6531" FILE *fp; int status; char load[30]; //open the command for reading fp = popen("cat /proc/loadavg", "r"); if(fp == NULL) { log_info("\nFailed to get LOAD\n"); } else { while(fgets(load, sizeof(load)-1, fp) != NULL) { log_info("\nRead data from cli: %s\n", load); } //closing pclose(fp); } //########################################## int numberOfLoadParams = 5; char *load_params[numberOfLoadParams]; int n=0; int nn; char *ds = strdup(load); load_params[n]=strtok(ds, " "); //log_info("load_params[%d]:%s",n,load_params[n]); while(load_params[n] && (n < (numberOfLoadParams-1))) { load_params[++n] = strtok(NULL, " "); // log_info("[LOG]load_params[%d]:%s",n,load_params[n]); } val_value_t *childval = NULL; childval = agt_make_list( obj_find_child(starter_get_load_obj,y_starter_M_starter,"output"), y_starter_N_load, &res); if(childval != NULL) { log_info("\nList found and initialized"); } val_value_t *a = NULL; /* char loadOne[40] = "load_One";*/ a = agt_make_leaf( childval->obj, y_starter_N_loadOne, (const xmlChar*)load_params[0], &res); if(a!=NULL) { log_info("\nloadOne filled with "); log_info(load_params[0]); val_add_child(a,childval); } else { return res; } /* char loadFive[40] = "load_Five";*/ a = agt_make_leaf( childval->obj, y_starter_N_loadFive, (const xmlChar*)load_params[1], &res); if(a!=NULL) { log_info("\nloadFive filled with "); log_info(load_params[1]); val_add_child(a,childval); } else { return res; } /* char loadFifteen[40] = "load_Fifteen";*/ a = agt_make_leaf( childval->obj, y_starter_N_loadFifteen, (const xmlChar*)load_params[2], &res); if(a!=NULL) { log_info("\nloadFifteen filled with "); log_info(load_params[2]); val_add_child(a,childval); } else { return res; } /* char processesCE[40] = "processesCurrentlyExists";*/ a = agt_make_leaf( childval->obj, y_starter_N_processesCurrentlyExists, (const xmlChar*)load_params[3], &res); if(a!=NULL) { log_info("\nprocessesCE filled with "); log_info(load_params[3]); val_add_child(a,childval); } else { return res; } /*log_info("PID: %s", load_params[4]);*/ //we need to remove the trailing \n from the end char* pid = strtok(load_params[4],"\n"); a = agt_make_leaf( childval->obj, y_starter_N_pid, (const xmlChar*)pid, &res); if(a!=NULL) { log_info("\npid filled with "); log_info(pid); val_add_child(a,childval); } else { return res; } free(ds); dlq_enque((void*)childval,&(msg->rpc_dataQ)); /* // ------------------------ CREATING A CUSTOM RPC REPLY ------------------------------- //declare a val_value_t * paramter val_value_t *rpc_output = NULL; //making a leaf // 1.param -> we need to find the corresponding output element defined in the yang // starter_get_load_obj is created automatically, since we have a get_load rpc in our module called starter -> starter_get_load_obj // y_starter_M_starter corresponds to the module (you need to modify both strings 'starter' to your module name) // "output" -> is the output part of the rpc (leave unmodified) // 2.param -> y_yourModuleName_N_leafNodeInYourRPCOUTPUT // 3.param -> the message you want to send (should be xmlChar*, char, char*) // 4. param -> the res variable which is returned by default rpc_output = agt_make_leaf( obj_find_child(starter_get_load_obj,y_starter_M_starter,"output"), y_starter_N_load, load, &res); //check that we could create correctly our RPC reply message if (rpc_output!=NULL) { //if yes -> put that to the rpc-reply (only rpc_output variable should be modified) dlq_enque((void*)rpc_output,&(msg->rpc_dataQ)); } //if, however, something went wrong during creating rpc-reply, we print it into the log else { log_error( "\nError: make leaf failed (%s), cannot send " "<load> rpc_reply", get_error_string(res)); } //====================================================================================== */ /********************************** END OF LEVI **************************************/ return res; } /* y_starter_starter_get_load_invoke */
/******************************************************************** * FUNCTION yangcli_notification_handler * * matches callback template mgr_not_cbfn_t * * INPUTS: * scb == session receiving RPC reply * msg == notification msg that was parsed * consumed == address of return consumed message flag * * OUTPUTS: * *consumed == TRUE if msg has been consumed so * it will not be freed by mgr_not_dispatch * == FALSE if msg has been not consumed so * it will be freed by mgr_not_dispatch *********************************************************************/ void yangcli_notification_handler (ses_cb_t *scb, mgr_not_msg_t *msg, boolean *consumed) { assert(scb && "scb is NULL!"); assert(msg && "msg is NULL!"); assert(consumed && "consumed is NULL!"); *consumed = FALSE; mgr_scb_t *mgrcb = scb->mgrcb; server_cb_t *server_cb = get_cur_server_cb(); session_cb_t *save_session_cb = server_cb->cur_session_cb; session_cb_t *session_cb = NULL; if (mgrcb) { session_cb = mgrcb->session_cb; } if (session_cb == NULL) { log_error("\nError: session no longer valid; dropping notification"); return; } const xmlChar *sesname = get_session_name(session_cb); if (session_cb != save_session_cb) { set_cur_session_cb(server_cb, session_cb); } /* check the contents of the notification */ if (msg && msg->notification) { /* dispatch this event to any handler registered for * this event; !!! not session-specific !!! */ uint32 retcnt = dispatch_notif_event(session_cb, msg); /* display only unhandled notifications, and only if * the session is configured to show them */ log_debug_t loglevel = log_get_debug_level(); log_debug_t base_loglevel = loglevel + 1; if (loglevel == LOG_DEBUG_INFO) { base_loglevel++; } if (retcnt == 0 && session_cb->echo_notifs && base_loglevel >= session_cb->echo_notif_loglevel) { gl_normal_io(server_cb->cli_gl); if (loglevel >= session_cb->echo_notif_loglevel) { log_write("\n\nIncoming notification for session %u [%s]:", scb->sid, sesname); val_dump_value_max(msg->notification, 0, session_cb->defindent, DUMP_VAL_LOG, session_cb->display_mode, FALSE, FALSE); log_write_append("\n\n"); } else if (msg->eventType) { log_write("\n\nIncoming <%s> notification for session " "%u [%s]\n\n", msg->eventType->name, scb->sid, sesname); } } /* store msg in the session notification log */ dlq_enque(msg, &session_cb->notificationQ); *consumed = TRUE; } if (session_cb != save_session_cb) { set_cur_session_cb(server_cb, save_session_cb); } } /* yangcli_notification_handler */
/******************************************************************** * 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 */
/******************************************************************** * FUNCTION yang_ext_consume_extension * * Parse the next N tokens as an extension-stmt * Create an ext_template_t struct and add it to the specified Q * * Error messages are printed by this function!! * Do not duplicate error messages upon error return * * Current token is the 'extension' keyword * * INPUTS: * tkc == token chain * mod == module in progress * * RETURNS: * status of the operation *********************************************************************/ status_t yang_ext_consume_extension (tk_chain_t *tkc, ncx_module_t *mod) { ext_template_t *ext, *testext; const xmlChar *val; const char *expstr; yang_stmt_t *stmt; tk_type_t tktyp; boolean done, arg, stat, desc, ref; status_t res, retres; #ifdef DEBUG if (!tkc || !mod) { return SET_ERROR(ERR_INTERNAL_PTR); } #endif val = NULL; expstr = "keyword"; done = FALSE; arg = FALSE; stat = FALSE; desc = FALSE; ref = FALSE; res = NO_ERR; retres = NO_ERR; /* Get a new ext_template_t to fill in */ ext = ext_new_template(); if (!ext) { res = ERR_INTERNAL_MEM; ncx_print_errormsg(tkc, mod, res); return res; } ncx_set_error(&ext->tkerr, mod, TK_CUR_LNUM(tkc), TK_CUR_LPOS(tkc)); /* Get the mandatory extension name */ res = yang_consume_id_string(tkc, mod, &ext->name); CHK_EXT_EXIT; /* Get the starting left brace for the sub-clauses * or a semi-colon to end the extension-stmt */ res = TK_ADV(tkc); if (res != NO_ERR) { ncx_print_errormsg(tkc, mod, res); ext_free_template(ext); return res; } switch (TK_CUR_TYP(tkc)) { case TK_TT_SEMICOL: done = TRUE; break; case TK_TT_LBRACE: break; default: retres = ERR_NCX_WRONG_TKTYPE; expstr = "semi-colon or left brace"; ncx_mod_exp_err(tkc, mod, retres, expstr); done = TRUE; } /* get the extension statements and any appinfo extensions */ while (!done) { /* get the next token */ res = TK_ADV(tkc); if (res != NO_ERR) { ncx_print_errormsg(tkc, mod, res); ext_free_template(ext); return res; } tktyp = TK_CUR_TYP(tkc); val = TK_CUR_VAL(tkc); /* check the current token type */ switch (tktyp) { case TK_TT_NONE: res = ERR_NCX_EOF; ncx_print_errormsg(tkc, mod, res); ext_free_template(ext); return res; case TK_TT_MSTRING: /* vendor-specific clause found instead */ res = ncx_consume_appinfo(tkc, mod, &ext->appinfoQ); CHK_EXT_EXIT; continue; case TK_TT_RBRACE: done = TRUE; continue; case TK_TT_TSTRING: break; /* YANG clause assumed */ default: retres = ERR_NCX_WRONG_TKTYPE; ncx_mod_exp_err(tkc, mod, retres, expstr); continue; } /* Got a token string so check the value */ if (!xml_strcmp(val, YANG_K_ARGUMENT)) { res = consume_yang_arg(tkc, mod, ext, &arg); } else if (!xml_strcmp(val, YANG_K_STATUS)) { res = yang_consume_status(tkc, mod, &ext->status, &stat, &ext->appinfoQ); } else if (!xml_strcmp(val, YANG_K_DESCRIPTION)) { res = yang_consume_descr(tkc, mod, &ext->descr, &desc, &ext->appinfoQ); } else if (!xml_strcmp(val, YANG_K_REFERENCE)) { res = yang_consume_descr(tkc, mod, &ext->ref, &ref, &ext->appinfoQ); } else { res = ERR_NCX_WRONG_TKVAL; ncx_mod_exp_err(tkc, mod, res, expstr); } CHK_EXT_EXIT; } /* save or delete the ext_template_t struct */ if (ext->name && ncx_valid_name2(ext->name)) { testext = ext_find_extension_all(mod, ext->name); if (testext) { log_error("\nError: extension '%s' already defined " "in '%s' at line %u", ext->name, testext->tkerr.mod->name, testext->tkerr.linenum); retres = ERR_NCX_DUP_ENTRY; ncx_print_errormsg(tkc, mod, retres); ext_free_template(ext); } else { dlq_enque(ext, &mod->extensionQ); /* may have some errors */ if (mod->stmtmode) { stmt = yang_new_ext_stmt(ext); if (stmt) { dlq_enque(stmt, &mod->stmtQ); } else { log_error("\nError: malloc failure for ext_stmt"); retres = ERR_INTERNAL_MEM; ncx_print_errormsg(tkc, mod, retres); } } } } else { ext_free_template(ext); } return retres; } /* yang_ext_consume_extension */