/******************************************************************** * FUNCTION dump_error_info * * Dump the error-info struct * * INPUTS: * errinfo == rpc_err_info_t struct to dump * *********************************************************************/ static void dump_error_info (const rpc_err_info_t *errinfo) { const xmlChar *prefix; log_write("\n error-info: %s T:%s = ", (errinfo->name) ? (const char *)errinfo->name : "--", tk_get_btype_sym(errinfo->val_btype)); if (errinfo->isqname) { prefix = xmlns_get_ns_prefix(errinfo->val_nsid); log_write("%s:%s", (prefix) ? prefix : (const xmlChar *)"--", (errinfo->v.strval) ? (const char *)errinfo->v.strval : "--"); return; } switch (errinfo->val_btype) { case NCX_BT_BINARY: case NCX_BT_STRING: case NCX_BT_INSTANCE_ID: log_write("%s", (errinfo->v.strval) ? (const char *)errinfo->v.strval : "--"); break; case NCX_BT_BOOLEAN: SET_ERROR(ERR_NCX_OPERATION_NOT_SUPPORTED); /***/ break; case NCX_BT_INT8: case NCX_BT_INT16: case NCX_BT_INT32: case NCX_BT_INT64: case NCX_BT_UINT8: case NCX_BT_UINT16: case NCX_BT_UINT32: case NCX_BT_UINT64: case NCX_BT_DECIMAL64: case NCX_BT_FLOAT64: ncx_printf_num(&errinfo->v.numval, errinfo->val_btype); break; default: val_dump_value((val_value_t *)errinfo->v.cpxval, NCX_DEF_INDENT*2); } } /* dump_error_info */
/******************************************************************** * FUNCTION parse_parm * * Parse, and fill one val_value_t struct during * processing of a parmset * * Error messages are printed by this function!! * Do not duplicate error messages upon error return * * * INPUTS: * tkc == token chain * val == container val to fill in * keepvals == TRUE to save existing parms in 'ps', as needed * FALSE to overwrite old parms in 'ps', as needed * * RETURNS: * status of the operation *********************************************************************/ static status_t parse_parm (tk_chain_t *tkc, val_value_t *val, boolean keepvals) { obj_template_t *obj; const xmlChar *modname; val_value_t *curparm, *newparm; status_t res; ncx_iqual_t iqual; boolean match, usewarning, isdefault; /* get the next token, which must be a TSTRING * representing the parameter name */ if (TK_CUR_TYP(tkc) != TK_TT_TSTRING) { res = ERR_NCX_WRONG_TKTYPE; ncx_conf_exp_err(tkc, res, "parameter name"); return res; } curparm = NULL; usewarning = ncx_warning_enabled(ERR_NCX_CONF_PARM_EXISTS); /* check if this TSTRING is a parameter in this parmset * make sure to always check for prefix:identifier * This is automatically processed in tk.c */ if (TK_CUR_MOD(tkc)) { modname = xmlns_get_module (xmlns_find_ns_by_prefix(TK_CUR_MOD(tkc))); if (modname) { curparm = val_find_child(val, modname, TK_CUR_VAL(tkc)); } } else { curparm = val_find_child(val, val_get_mod_name(val), TK_CUR_VAL(tkc)); } if (curparm) { obj = curparm->obj; } else { obj = obj_find_child(val->obj, TK_CUR_MOD(tkc), TK_CUR_VAL(tkc)); } if (!obj) { res = ERR_NCX_UNKNOWN_PARM; if (TK_CUR_MOD(tkc)) { log_error("\nError: parameter '%s:%s' not found", TK_CUR_MOD(tkc), TK_CUR_VAL(tkc)); } else { log_error("\nError: parameter '%s' not found", TK_CUR_VAL(tkc)); } ncx_conf_exp_err(tkc, res, "parameter name"); return res; } /* got a valid parameter name, now create a new parm * even if it may not be kept. There are corner-cases * that require the new value be parsed before knowing * if a parm value is a duplicate or not */ newparm = val_new_value(); if (!newparm) { res = ERR_INTERNAL_MEM; ncx_print_errormsg(tkc, NULL, res); return res; } val_init_from_template(newparm, obj); /* parse the parameter value */ res = parse_val(tkc, obj, newparm); if (res != NO_ERR) { val_free_value(newparm); return res; } /* check if a potential current value exists, or just * add the newparm to the parmset */ if (curparm) { isdefault = val_set_by_default(curparm); iqual = obj_get_iqualval(obj); if (iqual == NCX_IQUAL_ONE || iqual == NCX_IQUAL_OPT) { /* only one allowed, check really a match */ match = TRUE; if (val_has_index(curparm) && !val_index_match(newparm, curparm)) { match = FALSE; } if (!match) { val_add_child(newparm, val); } else if (isdefault) { dlq_remove(curparm); val_free_value(curparm); val_add_child(newparm, val); } else if (keepvals) { if (usewarning) { /* keep current value and toss new value */ log_warn("\nWarning: Parameter '%s' already exists. " "Not using new value\n", curparm->name); if (LOGDEBUG2) { val_dump_value(newparm, NCX_DEF_INDENT); log_debug2("\n"); } } val_free_value(newparm); } else { if (usewarning) { /* replace current value and warn old value tossed */ log_warn("\nconf: Parameter '%s' already exists. " "Overwriting with new value\n", curparm->name); if (LOGDEBUG2) { val_dump_value(newparm, NCX_DEF_INDENT); log_debug2("\n"); } } dlq_remove(curparm); val_free_value(curparm); val_add_child(newparm, val); } } else { /* mutliple instances allowed */ val_add_child(newparm, val); } } else { val_add_child(newparm, val); } return NO_ERR; } /* parse_parm */
/******************************************************************** * 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 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 */