/* Destructively merge a new config tree into an existing one */ int merge_config_tree(struct cmd_context *cmd, struct dm_config_tree *cft, struct dm_config_tree *newdata, config_merge_t merge_type) { struct dm_config_node *root = cft->root; struct dm_config_node *cn, *nextn, *oldn, *cn2; const struct dm_config_node *tn; struct config_source *cs, *csn; for (cn = newdata->root; cn; cn = nextn) { nextn = cn->sib; if (merge_type == CONFIG_MERGE_TYPE_TAGS) { /* Ignore tags section */ if (!strcmp(cn->key, "tags")) continue; /* If there's a tags node, skip if host tags don't match */ if ((tn = dm_config_find_node(cn->child, "tags"))) { if (!_match_host_tags(&cmd->tags, tn)) continue; } } if (!(oldn = dm_config_find_node(root, cn->key))) { _insert_config_node(&cft->root, cn); if (merge_type == CONFIG_MERGE_TYPE_TAGS) { /* Remove any "tags" nodes */ for (cn2 = cn->child; cn2; cn2 = cn2->sib) { if (!strcmp(cn2->key, "tags")) { cn->child = cn2->sib; continue; } if (cn2->sib && !strcmp(cn2->sib->key, "tags")) { cn2->sib = cn2->sib->sib; continue; } } } continue; } _merge_section(oldn, cn, merge_type); } /* * Persistent filter loading is based on timestamp, * so we need to know the newest timestamp to make right decision * whether the .cache isn't older then any of configs */ cs = dm_config_get_custom(cft); csn = dm_config_get_custom(newdata); if (cs && csn && (cs->timestamp < csn->timestamp)) cs->timestamp = csn->timestamp; return 1; }
/* * Merge section cn2 into section cn1 (which has the same name) * overwriting any existing cn1 nodes with matching names. */ static void _merge_section(struct dm_config_node *cn1, struct dm_config_node *cn2, config_merge_t merge_type) { struct dm_config_node *cn, *nextn, *oldn; struct dm_config_value *cv; for (cn = cn2->child; cn; cn = nextn) { nextn = cn->sib; if (merge_type == CONFIG_MERGE_TYPE_TAGS) { /* Skip "tags" */ if (!strcmp(cn->key, "tags")) continue; } /* Subsection? */ if (!cn->v) /* Ignore - we don't have any of these yet */ continue; /* Not already present? */ if (!(oldn = dm_config_find_node(cn1->child, cn->key))) { _insert_config_node(&cn1->child, cn); continue; } if (merge_type == CONFIG_MERGE_TYPE_TAGS) { /* Merge certain value lists */ if ((!strcmp(cn1->key, "activation") && !strcmp(cn->key, "volume_list")) || (!strcmp(cn1->key, "devices") && (!strcmp(cn->key, "filter") || !strcmp(cn->key, "types")))) { cv = cn->v; while (cv->next) cv = cv->next; cv->next = oldn->v; } } /* Replace values */ oldn->v = cn->v; } }
/* Destructively merge a new config tree into an existing one */ int merge_config_tree(struct cmd_context *cmd, struct config_tree *cft, struct config_tree *newdata) { const struct config_node *root = cft->root; struct config_node *cn, *nextn, *oldn, *cn2; const struct config_node *tn; for (cn = newdata->root; cn; cn = nextn) { nextn = cn->sib; /* Ignore tags section */ if (!strcmp(cn->key, "tags")) continue; /* If there's a tags node, skip if host tags don't match */ if ((tn = find_config_node(cn->child, "tags"))) { if (!_match_host_tags(&cmd->tags, tn)) continue; } if (!(oldn = (struct config_node *)find_config_node(root, cn->key))) { _insert_config_node(&cft->root, cn); /* Remove any "tags" nodes */ for (cn2 = cn->child; cn2; cn2 = cn2->sib) { if (!strcmp(cn2->key, "tags")) { cn->child = cn2->sib; continue; } if (cn2->sib && !strcmp(cn2->sib->key, "tags")) { cn2->sib = cn2->sib->sib; continue; } } continue; } _merge_section(oldn, cn); } return 1; }