bool merge_recursive(ucl_object_t *top, ucl_object_t *elt, bool copy) { const ucl_object_t *cur; ucl_object_iter_t it = NULL; ucl_object_t *found = NULL, *cp_obj = NULL; bool success = false; it = ucl_object_iterate_new(elt); while ((cur = ucl_object_iterate_safe(it, false))) { cp_obj = ucl_object_ref(cur); if (debug > 0) { fprintf(stderr, "DEBUG: Looping over (elt)%s, found key: %s\n", ucl_object_key(top), ucl_object_key(cur)); } if (ucl_object_type(cur) == UCL_OBJECT) { found = __DECONST(ucl_object_t *, ucl_object_find_key(top, ucl_object_key(cur))); if (found == NULL) { /* new key not found in old object, insert it */ if (debug > 0) { fprintf(stderr, "DEBUG: unmatched key, inserting: %s into top\n", ucl_object_key(cur)); } success = ucl_object_insert_key_merged(top, cp_obj, ucl_object_key(cp_obj), 0, true); if (success == false) { return false; } continue; } if (debug > 0) { fprintf(stderr, "DEBUG: (obj) Found key %s in (top)%s too, merging...\n", ucl_object_key(found), ucl_object_key(top)); } success = merge_recursive(found, cp_obj, copy); if (success == false) { return false; } } else if (ucl_object_type(cur) == UCL_ARRAY) {
/* Do post load initialization based on lua */ void rspamd_lua_post_load_config (struct rspamd_config *cfg) { lua_State *L = cfg->lua_state; const gchar *name, *val; gchar *sym; struct rspamd_expression *expr, *old_expr; ucl_object_t *obj; gsize keylen; GError *err = NULL; /* First check all module options that may be overriden in 'config' global */ lua_getglobal (L, "config"); if (lua_istable (L, -1)) { /* Iterate */ for (lua_pushnil (L); lua_next (L, -2); lua_pop (L, 1)) { /* 'key' is at index -2 and 'value' is at index -1 */ /* Key must be a string and value must be a table */ name = luaL_checklstring (L, -2, &keylen); if (name != NULL && lua_istable (L, -1)) { obj = ucl_object_lua_import (L, lua_gettop (L)); if (obj != NULL) { ucl_object_insert_key_merged (cfg->rcl_obj, obj, name, keylen, true); } } } } /* Check metrics settings */ lua_getglobal (L, "metrics"); if (lua_istable (L, -1)) { /* Iterate */ for (lua_pushnil (L); lua_next (L, -2); lua_pop (L, 1)) { /* 'key' is at index -2 and 'value' is at index -1 */ /* Key must be a string and value must be a table */ name = luaL_checkstring (L, -2); if (name != NULL && lua_istable (L, -1)) { lua_process_metric (L, name, cfg); } } } /* Check composites */ lua_getglobal (L, "composites"); if (lua_istable (L, -1)) { /* Iterate */ for (lua_pushnil (L); lua_next (L, -2); lua_pop (L, 1)) { /* 'key' is at index -2 and 'value' is at index -1 */ /* Key must be a string and value must be a table */ name = luaL_checkstring (L, -2); if (name != NULL && lua_isstring (L, -1)) { val = lua_tostring (L, -1); sym = rspamd_mempool_strdup (cfg->cfg_pool, name); if (!rspamd_parse_expression (val, 0, &composite_expr_subr, NULL, cfg->cfg_pool, &err, &expr)) { msg_err_config("cannot parse composite expression '%s': %s", val, err->message); g_error_free (err); err = NULL; continue; } /* Now check hash table for this composite */ if ((old_expr = g_hash_table_lookup (cfg->composite_symbols, name)) != NULL) { msg_info_config("replacing composite symbol %s", name); g_hash_table_replace (cfg->composite_symbols, sym, expr); } else { g_hash_table_insert (cfg->composite_symbols, sym, expr); rspamd_symbols_cache_add_symbol (cfg->cache, sym, 0, NULL, NULL, SYMBOL_TYPE_COMPOSITE, -1); } } } } }
int merge_mode(char *destination_node, char *data) { ucl_object_t *dst_obj = NULL; ucl_object_t *sub_obj = NULL; ucl_object_t *old_obj = NULL; ucl_object_t *tmp_obj = NULL; int success = 0; char *dst_frag; setparser = ucl_parser_new(UCL_PARSER_KEY_LOWERCASE | UCL_PARSER_NO_IMPLICIT_ARRAYS); /* Lookup the destination to write to */ dst_obj = get_parent(destination_node); sub_obj = get_object(destination_node); if (sub_obj == NULL) { fprintf(stderr, "Failed to find destination node: %s\n", destination_node); return false; } if (include_file != NULL) { /* get UCL to add from file */ set_obj = parse_file(setparser, include_file); } else if (data == NULL || strcmp(data, "-") == 0) { /* get UCL to add from stdin */ set_obj = parse_input(setparser, stdin); } else { /* User provided data inline */ set_obj = parse_string(setparser, data); } if (debug > 0) { char *rt = NULL, *dt = NULL, *st = NULL; rt = objtype_as_string(dst_obj); dt = objtype_as_string(sub_obj); st = objtype_as_string(set_obj); fprintf(stderr, "root type: %s, destination type: %s, new type: %s\n", rt, dt, st); if (rt != NULL) free(rt); if (dt != NULL) free(dt); if (st != NULL) free(st); fprintf(stderr, "Merging key %s to root: %s\n", ucl_object_key(sub_obj), ucl_object_key(dst_obj)); } dst_frag = strrchr(destination_node, input_sepchar); if (dst_frag == NULL) { dst_frag = destination_node; } else { dst_frag++; } /* Add it to the object here */ if (sub_obj == dst_obj && *dst_frag != '\0') { /* Sub-object does not exist, create a new one */ success = ucl_object_insert_key(dst_obj, set_obj, dst_frag, 0, true); } else if (ucl_object_type(sub_obj) == UCL_ARRAY && ucl_object_type(set_obj) == UCL_ARRAY) { if (debug > 0) { fprintf(stderr, "Merging array of size %u with array of size %u\n", sub_obj->len, set_obj->len); } success = ucl_array_merge(sub_obj, set_obj, true); } else if (ucl_object_type(sub_obj) == UCL_ARRAY) { if (debug > 0) { fprintf(stderr, "Appending object to array of size %u\n", sub_obj->len); } success = ucl_array_append(sub_obj, ucl_object_ref(set_obj)); } else if (ucl_object_type(sub_obj) == UCL_OBJECT && ucl_object_type(set_obj) == UCL_OBJECT) { if (debug > 0) { fprintf(stderr, "Merging object %s with object %s\n", ucl_object_key(sub_obj), ucl_object_key(set_obj)); } /* XXX not supported: * success = ucl_object_merge(sub_obj, set_obj, false, true); */ /* Old non-recursive way */ /* success = ucl_object_merge(sub_obj, set_obj, false); */ success = merge_recursive(sub_obj, set_obj, false); } else if (ucl_object_type(sub_obj) != UCL_OBJECT && ucl_object_type(sub_obj) != UCL_ARRAY) { /* Create an explicit array */ if (debug > 0) { fprintf(stderr, "Creating an array and appended the new item\n"); } tmp_obj = ucl_object_typed_new(UCL_ARRAY); /* * Reference and Append the original scalar * The additional reference is required because the old object will be * unreferenced as part of the ucl_object_replace_key operation */ ucl_array_append(tmp_obj, ucl_object_ref(sub_obj)); /* Reference and Append the new scalar (unref in cleanup()) */ ucl_array_append(tmp_obj, ucl_object_ref(set_obj)); /* Replace the old object with the newly created one */ if (ucl_object_type(dst_obj) == UCL_ARRAY) { old_obj = ucl_array_replace_index(dst_obj, tmp_obj, ucl_array_index_of(dst_obj, sub_obj)); success = false; if (old_obj != NULL) { ucl_object_unref(old_obj); success = true; } } else { success = ucl_object_replace_key(dst_obj, tmp_obj, ucl_object_key(sub_obj), 0, true); } } else { if (debug > 0) { fprintf(stderr, "Merging object into key %s\n", ucl_object_key(sub_obj)); } success = ucl_object_insert_key_merged(dst_obj, ucl_object_ref(set_obj), ucl_object_key(sub_obj), 0, true); } return success; }