/* Retrieve a named element content and attributes */ char *xml_get_named_with_attributes( const char *xml, const char *name, char *content, size_t sizeof_content, char *attributes, size_t sizeof_attributes ) { struct xml_info info; xml = xml_find_named( xml, name, &info ); if ( xml == NULL ) return NULL; if ( attributes != NULL ) xml_strcpy( attributes, sizeof_attributes, info.attributes, info.end_of_attributes ); return xml_strcpy( content, sizeof_content, info.content, info.end_of_content ); }
/* Retrieve the content of the given element */ char *xml_get_content( const char *element, char* content, size_t sizeof_content ) { struct xml_info info; if ( xml_get_element_info( element, &info, STOP_AFTER_CONTENT ) ) return xml_strcpy( content, sizeof_content, info.content, info.end_of_content ); return NULL; }
/* Retrieve the name of the given element */ char *xml_get_name( const char *element, char *name, size_t sizeof_name ) { struct xml_info info; if ( xml_get_element_info( element, &info, STOP_AFTER_NAME ) ) return xml_strcpy( name, sizeof_name, info.name, info.end_of_name ); return NULL; }
/* Retrieve the attributes of the given element */ char *_xml_get_attributes( const char *element, char *attributes, size_t sizeof_attributes ) { struct xml_info info; if ( xml_get_element_info( element, &info, STOP_AFTER_ATTRIBUTES ) ) return xml_strcpy( attributes, sizeof_attributes, info.attributes, info.end_of_attributes ); return NULL; }
/* Retrieve a named attribute value */ char *xml_get_named_attribute( const char *element, const char *name, char *value, size_t sizeof_value ) { struct xml_info info; if ( xml_find_named_attribute( element, name, &info ) ) return xml_strcpy( value, sizeof_value, info.content, info.end_of_content ); return NULL; }
/******************************************************************** * FUNCTION output_pattern_diff * * Output the differences report for one pattern clause and * any of its sub-clauses, within a leaf, leaf-list, or * typedef definition * * INPUTS: * cp == parameter block to use * oldpat == old internal pattern * newpat == new internal pattern * patnum == index number of pattern in the Q [1 .. N] * *********************************************************************/ static void output_pattern_diff (yangdiff_diffparms_t *cp, const typ_pattern_t *oldpat, const typ_pattern_t *newpat, uint32 patnum) { const ncx_errinfo_t *olderr, *newerr; const xmlChar *oldstr, *newstr; xmlChar buff[NCX_MAX_NUMLEN+16], *p; oldstr = (oldpat) ? oldpat->pat_str : NULL; newstr = (newpat) ? newpat->pat_str : NULL; olderr = (oldpat) ? &oldpat->pat_errinfo : NULL; newerr = (newpat) ? &newpat->pat_errinfo : NULL; p = buff; p += xml_strcpy(p, YANG_K_PATTERN); *p++ = ' '; *p++ = '['; p += (uint32)sprintf((char *)p, "%u", patnum); *p++ = ']'; *p = 0; if (!oldstr && newstr) { /* pattern added in new revision */ output_diff(cp, buff, oldstr, newstr, FALSE); indent_in(cp); output_errinfo_diff(cp, olderr, newerr); indent_out(cp); } else if (oldstr && !newstr) { /* pattern removed in new revision */ output_diff(cp, buff, oldstr, newstr, FALSE); indent_in(cp); output_errinfo_diff(cp, olderr, newerr); indent_out(cp); } else if (oldstr && newstr) { /* check if pattern changed */ if (xml_strcmp(oldstr, newstr)) { output_diff(cp, buff, oldstr, newstr, FALSE); indent_in(cp); output_errinfo_diff(cp, olderr, newerr); indent_out(cp); } else if (errinfo_changed(olderr, newerr)) { output_mstart_line(cp, buff, oldstr, FALSE); indent_in(cp); output_errinfo_diff(cp, olderr, newerr); indent_out(cp); } } } /* output_pattern_diff */
static int match_nodes( const mxml_char_t * path, size_t *path_len, mxml_node *n, LIST_TYPE lst ) { #define XPATH_MAX_LEN 128 mxml_char_t buffer [XPATH_MAX_LEN]; const mxml_char_t * slash_ptr = xml_strchr( path, (mxml_char_t)('/') ); const size_t length = slash_ptr ? (size_t)(slash_ptr - path) : 0; match m; if ( length >= XPATH_MAX_LEN ) return -1; memset( buffer, 0, XPATH_MAX_LEN * sizeof( mxml_char_t ) ); //* if ( length ) xml_strncpy( buffer, path, length ); else xml_strcpy( buffer, path ); init_str( &m.value ); init_str( &m.pred.cond_value ); init_str( &m.pred.value ); if ( 0 == identify_match( buffer, &m ) ) { if ( 0 != xpath_match( lst, n, &m ) ) return -1; else { *path_len = length; return 0; } } //*/ return -1; #undef XPATH_MAX_LEN }
/******************************************************************** * FUNCTION expand_alias * * Check if the first token is an alias name * If so, construct a new command line with the alias contents * * INPUT: * line == command line to check and possibly convert * res == address of return status * * OUTPUTS: * *res == return status (ERR_NCX_SKIPPED if nothing done) * * RETURNS: * pointer to malloced command string if *res==NO_ERR * NULL if *res==ERR_NCX_SKIPPED or some real error *********************************************************************/ xmlChar * expand_alias (xmlChar *line, status_t *res) { xmlChar *start, *p = line, *newline; alias_cb_t *alias; uint32 namelen, newlen; boolean done = FALSE; /* skip any leading whitespace; not expected from yangcli */ while (*p && xml_isspace(*p)) { p++; } if (*p == 0) { *res = ERR_NCX_SKIPPED; return NULL; } /* look for end of name */ start = p; if (!ncx_valid_fname_ch(*p++)) { *res = ERR_NCX_SKIPPED; return NULL; } while (*p && !done) { if (xml_isspace(*p)) { done = TRUE; } else if (!ncx_valid_name_ch(*p)) { *res = ERR_NCX_SKIPPED; return NULL; } else { p++; } } /* look for the alias */ namelen = (uint32)(p - start); alias = find_alias(start, namelen); if (alias == NULL) { *res = ERR_NCX_SKIPPED; return NULL; } /* replace the alias name with its contents and make a new string */ if (alias->value) { newlen = xml_strlen(p) + xml_strlen(alias->value); } else { newlen = xml_strlen(p); } newline = m__getMem(newlen + 1); if (newline == NULL) { *res = ERR_INTERNAL_MEM; return NULL; } start = newline; if (alias->value) { start += xml_strcpy(start, alias->value); } xml_strcpy(start, p); if (LOGDEBUG2) { log_debug2("\nExpanded alias '%s'; new line: '%s'", alias->name, newline); } *res = NO_ERR; return newline; } /* expand_alias */
/******************************************************************** * FUNCTION set_initial_transaction_id * * Set the last_transaction_id for the running config * Will check for sys:transaction-id leaf in config->root * * RETURNS: * status *********************************************************************/ static status_t set_initial_transaction_id (void) { cfg_template_t *cfg = cfg_get_config_id(NCX_CFGID_RUNNING); if (cfg == NULL) { return ERR_NCX_CFG_NOT_FOUND; } if (cfg->root == NULL) { return ERR_NCX_EMPTY_VAL; } agt_profile_t *profile = agt_get_profile(); status_t res = NO_ERR; boolean foundfile = FALSE; /* figure out which transaction ID file to use */ if (profile->agt_startup_txid_file == NULL) { /* search for the default startup-cfg.xml filename */ xmlChar *fname = ncxmod_find_data_file(NCX_DEF_STARTUP_TXID_FILE, FALSE, &res); if (fname == NULL || res != NO_ERR || *fname == 0) { /* need to set the default startup transaction ID file name */ log_debug("\nSetting initial transaction ID file to default"); if (fname) { m__free(fname); } res = NO_ERR; fname = agt_get_startup_filespec(&res); if (fname == NULL || res != NO_ERR) { if (res == NO_ERR) { res = ERR_NCX_OPERATION_FAILED; } log_error("\nFailed to set initial transaction ID file (%s)", get_error_string(res)); if (fname) { m__free(fname); } return res; } /* get dir part and append the TXID file name to it */ uint32 fnamelen = xml_strlen(fname); xmlChar *str = &fname[fnamelen - 1]; while (str >= fname && *str && *str != NCX_PATHSEP_CH) { str--; } if (*str != NCX_PATHSEP_CH) { log_error("\nFailed to set initial transaction ID file"); m__free(fname); return ERR_NCX_INVALID_VALUE; } /* copy base filespec + 1 for the path-sep-ch */ uint32 baselen = (uint32)(str - fname) + 1; uint32 newlen = baselen + xml_strlen(NCX_DEF_STARTUP_TXID_FILE); xmlChar *newstr = m__getMem(newlen + 1); if (newstr == NULL) { m__free(fname); return ERR_INTERNAL_MEM; } str = newstr; str += xml_strncpy(str, fname, baselen); xml_strcpy(str, NCX_DEF_STARTUP_TXID_FILE); m__free(fname); profile->agt_startup_txid_file = newstr; // pass off memory here } else { foundfile = TRUE; profile->agt_startup_txid_file = fname; // pass off memory here } } /* initialize the starting transaction ID in the config module */ res = agt_cfg_init_transactions(profile->agt_startup_txid_file, foundfile); if (res != NO_ERR) { log_error("\nError: cfg-init transaction ID failed (%s)", get_error_string(res)); } return res; } /* set_initial_transaction_id */
/******************************************************************** * FUNCTION agt_ses_process_first_ready * * Check the readyQ and process the first message, if any * * RETURNS: * TRUE if a message was processed * FALSE if the readyQ was empty *********************************************************************/ boolean agt_ses_process_first_ready (void) { ses_cb_t *scb; ses_ready_t *rdy; ses_msg_t *msg; status_t res; uint32 cnt; xmlChar buff[32]; rdy = ses_msg_get_first_inready(); if (!rdy) { return FALSE; } /* get the session control block that rdy is embedded into */ scb = agtses[rdy->sid]; if (scb == NULL) { log_debug("\nagt_ses: session %d gone", rdy->sid); return FALSE; } log_debug2("\nagt_ses msg ready for session %d", scb->sid); /* check the session control block state */ if (scb->state >= SES_ST_SHUTDOWN_REQ) { /* don't process the message or even it mark it * It will be cleaned up when the session is freed */ log_debug("\nagt_ses drop input, session %d shutting down", scb->sid); return TRUE; } /* make sure a message is really there */ msg = (ses_msg_t *)dlq_firstEntry(&scb->msgQ); if (!msg || !msg->ready) { SET_ERROR(ERR_INTERNAL_PTR); log_error("\nagt_ses ready Q message not correct"); if (msg && scb->state != SES_ST_INIT) { /* do not echo the ncx-connect message */ cnt = xml_strcpy(buff, (const xmlChar *)"Incoming msg for session "); snprintf((char *)(&buff[cnt]), sizeof(buff) - cnt, "%u", scb->sid); ses_msg_dump(msg, buff); } return FALSE; } else if (LOGDEBUG2 && scb->state != SES_ST_INIT) { cnt = xml_strcpy(buff, (const xmlChar *)"Incoming msg for session "); snprintf((char *)(&buff[cnt]), sizeof(buff) - cnt, "%u", scb->sid); ses_msg_dump(msg, buff); } /* setup the XML parser */ if (scb->reader) { /* reset the xmlreader */ res = xml_reset_reader_for_session(ses_read_cb, NULL, scb, scb->reader); } else { res = xml_get_reader_for_session(ses_read_cb, NULL, scb, &scb->reader); } /* process the message */ if (res == NO_ERR) { /* process the message * the scb pointer may get deleted !!! */ agt_top_dispatch_msg(&scb); } else { if (LOGINFO) { log_info("\nReset xmlreader failed for session %d (%s)", scb->sid, get_error_string(res)); } agt_ses_kill_session(scb, 0, SES_TR_OTHER); scb = NULL; } if (scb) { /* free the message that was just processed */ dlq_remove(msg); ses_msg_free_msg(scb, msg); /* check if any messages left for this session */ msg = (ses_msg_t *)dlq_firstEntry(&scb->msgQ); if (msg && msg->ready) { ses_msg_make_inready(scb); } } return TRUE; } /* agt_ses_process_first_ready */
/******************************************************************** * FUNCTION output_one_type_diff * * Output the differences report for one type section * within a leaf, leaf-list, or typedef definition * * type_changed should be called first to determine * if the type actually changed. Otherwise a 'M typedef foo' * output line will result and be a false positive * * INPUTS: * cp == parameter block to use * oldtypdef == old internal typedef * newtypdef == new internal typedef * *********************************************************************/ void output_one_type_diff (yangdiff_diffparms_t *cp, typ_def_t *oldtypdef, typ_def_t *newtypdef) { xmlChar *p, *oldp, *newp; const xmlChar *oldname, *newname; const xmlChar *oldpath, *newpath; yangdiff_cdb_t typcdb[5]; ncx_btype_t oldbtyp, newbtyp; ncx_tclass_t oldclass, newclass; boolean isrev; isrev = (cp->edifftype==YANGDIFF_DT_REVISION) ? TRUE : FALSE; oldclass = oldtypdef->tclass; newclass = newtypdef->tclass; oldname = typ_get_name(oldtypdef); newname = typ_get_name(newtypdef); oldbtyp = typ_get_basetype(oldtypdef); newbtyp = typ_get_basetype(newtypdef); if (oldbtyp == NCX_BT_LEAFREF) { oldpath = typ_get_leafref_path(oldtypdef); } else { oldpath = NULL; } if (newbtyp==NCX_BT_LEAFREF) { newpath = typ_get_leafref_path(newtypdef); } else { newpath = NULL; } /* check if there is a module prefix involved * in the change. This may be a false positive * if the prefix simply changed * create YANG QNames for the type change record * use the scratch buffer cp->buff for both strings */ p = cp->buff; if (oldtypdef->prefix) { oldp = p; p += xml_strcpy(p, oldtypdef->prefix); *p++ = ':'; p += xml_strcpy(p, oldname); if (oldtypdef->tclass==NCX_CL_NAMED) { *p++ = ' '; *p++ = '('; p += xml_strcpy(p, (const xmlChar *) tk_get_btype_sym(oldbtyp)); *p++ = ')'; *p = 0; } p++; /* leave last NULL char in place */ oldname = oldp; } if (newtypdef->prefix) { newp = p; p += xml_strcpy(p, newtypdef->prefix); *p++ = ':'; p += xml_strcpy(p, newname); if (newtypdef->tclass==NCX_CL_NAMED) { *p++ = ' '; *p++ = '('; p += xml_strcpy(p, (const xmlChar *) tk_get_btype_sym(newbtyp)); *p++ = ')'; *p = 0; } newname = newp; } /* Print the type name change set only if it really * changed; otherwise force an M line to be printed */ if (str_field_changed(YANG_K_TYPE, oldname, newname, isrev, &typcdb[0])) { output_cdb_line(cp, &typcdb[0]); } else { output_mstart_line(cp, YANG_K_TYPE, NULL, FALSE); } /* check invalid change of builtin type */ if (oldbtyp != newbtyp) { /* need to figure out what type changes are really allowed */ if (!((typ_is_number(oldbtyp) && typ_is_number(newbtyp)) || (typ_is_string(oldbtyp) && typ_is_string(newbtyp)))) { /* ses_putstr(cp->scb, (const xmlChar *)" (invalid)"); */ return; } } /* check if that is all the data requested */ if (cp->edifftype == YANGDIFF_DT_TERSE) { return; } /* check corner-case, no sub-fields to compare */ if (oldclass==NCX_CL_BASE && newclass==NCX_CL_BASE) { /* type field is a plain builtin like 'int32;' */ return; } /* in all modes except 'normal', indent 1 level and * show the specific sub-clauses that have changed */ indent_in(cp); /* special case -- check leafref here */ if (oldpath || newpath) { output_diff(cp, YANG_K_PATH, oldpath, newpath, FALSE); } if (typ_is_number(oldbtyp)) { output_range_diff(cp, YANG_K_RANGE, oldtypdef, newtypdef); } else if (typ_is_string(oldbtyp)) { output_range_diff(cp, YANG_K_LENGTH, oldtypdef, newtypdef); output_patternQ_diff(cp, oldtypdef, newtypdef); } else { switch (oldbtyp) { case NCX_BT_ENUM: output_eb_type_diff(cp, oldtypdef, newtypdef, FALSE); break; case NCX_BT_BITS: output_eb_type_diff(cp, oldtypdef, newtypdef, TRUE); break; case NCX_BT_UNION: output_union_diff(cp, oldtypdef, newtypdef); break; default: ; } } indent_out(cp); } /* output_one_type_diff */
/******************************************************************** * FUNCTION xml_msg_gen_new_prefix * * Generate a new namespace prefix * * INPUTS: * msg == message to search and generate a prefix for * nsid == namespace ID to generate prefix for * retbuff == address of return buffer * buffsize == buffer size * OUTPUTS: * if *retbuff is NULL it will be created * else *retbuff is filled in with the new prefix if NO_ERR * * RETURNS: * status *********************************************************************/ status_t xml_msg_gen_new_prefix (xml_msg_hdr_t *msg, xmlns_id_t nsid, xmlChar **retbuff, uint32 buffsize) { const xmlChar *defpfix; xmlChar startch; int32 nlen, i; xmlChar numbuff[NCX_MAX_NUMLEN], *buff; xmlns_id_t testid; #ifdef DEBUG if (!msg || !retbuff) { return SET_ERROR(ERR_INTERNAL_PTR); } #endif if (*retbuff) { buff = *retbuff; } else { buff = m__getMem(NCX_MAX_NUMLEN+1); if (!buff) { return ERR_INTERNAL_MEM; } else { buffsize = NCX_MAX_NUMLEN+1; *retbuff = buff; } } /* first see if a default prefix was registered with the namespace * and use it if not already in the prefix map */ defpfix = xmlns_get_ns_prefix(nsid); if (defpfix && *defpfix) { testid = find_prefix_val(msg, defpfix); if (testid == 0 || testid==nsid) { if (xml_strlen(defpfix) < buffsize) { xml_strcpy(buff, defpfix); return NO_ERR; } else { return ERR_BUFF_OVFL; } } } /* default already in use for something else so generate a prefix */ nlen = snprintf((char *)numbuff, NCX_MAX_NUMLEN, "%u", (uint32)nsid); if (nlen < 0) { return ERR_NCX_INVALID_NUM; } if ((uint32)(nlen+2) >= buffsize) { return ERR_BUFF_OVFL; } /* copy the number to the prefix buffer w/ trailing zero */ for (i=0; i<=nlen; i++) { buff[i+1] = numbuff[i]; } /* set the start letter in the prefix buffer */ startch = 'n'; /* try to generate a unique prefix */ for (i=0; i<=MAX_PREFIX_TRIES; i++) { /* adjust the label value */ buff[0] = startch++; if (startch > 'z') { startch = 'a'; } /* check if the prefix is in use */ if (!find_prefix_val(msg, buff)) { return NO_ERR; } } return ERR_NCX_OPERATION_FAILED; } /* xml_msg_gen_new_prefix */