/* * Free an XML node */ void xml_node_free(xml_node_t *node) { xml_node_t *child; if (!node) return; ni_assert(node->refcount); if (--(node->refcount) != 0) return; while ((child = node->children) != NULL) { node->children = child->next; xml_node_free(child); } if (node->location) xml_location_free(node->location); ni_var_array_destroy(&node->attrs); free(node->cdata); free(node->name); free(node); }
ni_bool_t ni_iaid_map_to_vars(const ni_iaid_map_t *map, ni_var_array_t *vars) { xml_node_t *root, *node = NULL; const char *name; if (!vars) return FALSE; if (!(root = ni_iaid_map_root_node(map))) return FALSE; ni_var_array_destroy(vars); while ((node = ni_iaid_map_next_node(root, node))) { if (ni_string_empty(node->cdata)) continue; name = xml_node_get_attr(node, NI_CONFIG_DEFAULT_IAID_DEVICE); if (ni_string_empty(name)) continue; ni_var_array_set(vars, name, node->cdata); } return TRUE; }
static int ni_do_duid_dump(int argc, char **argv) { enum { OPT_HELP = 'h' }; static struct option options[] = { { "help", no_argument, NULL, OPT_HELP }, { NULL, no_argument, NULL, 0 } }; int opt = 0, status = NI_WICKED_RC_USAGE; ni_var_array_t vars = NI_VAR_ARRAY_INIT; ni_duid_map_t *map = NULL; ni_var_t *var; optind = 1; while ((opt = getopt_long(argc, argv, "+h", options, NULL)) != EOF) { switch (opt) { case OPT_HELP: status = NI_WICKED_RC_SUCCESS; default: usage: fprintf(stderr, "Usage: %s [options]\n" "\n" "Options:\n" " --help, -h show this help text and exit.\n" "\n", argv[0]); goto cleanup; } } if (argc - optind) goto usage; status = NI_WICKED_RC_ERROR; if (!(map = ni_duid_map_load(NULL))) goto cleanup; status = NI_WICKED_RC_SUCCESS; if (ni_duid_map_to_vars(map, &vars)) { unsigned int i; for (i = 0, var = vars.data; i < vars.count; ++i, ++var) { printf("%s\t%s\n", var->name ? var->name : "default", var->value); } ni_var_array_destroy(&vars); } cleanup: ni_duid_map_free(map); return status; }
void ni_var_array_copy(ni_var_array_t *dst, const ni_var_array_t *src) { unsigned int i; ni_var_array_destroy(dst); __ni_var_array_realloc(dst, src->count); for (i = 0; i < src->count; ++i) { const ni_var_t *sv = &src->data[i]; ni_var_t *dv = &dst->data[i]; ni_string_dup(&dv->name, sv->name); ni_string_dup(&dv->value, sv->value); } }
ni_bool_t ni_config_parse_addrconf_dhcp6(struct ni_config_dhcp6 *dhcp6, xml_node_t *node) { xml_node_t *child; for (child = node->children; child; child = child->next) { const char *attrval; if (!strcmp(child->name, "default-duid") && !ni_string_empty(child->cdata)) { ni_string_dup(&dhcp6->default_duid, child->cdata); } else if (!strcmp(child->name, "user-class")) { ni_string_array_destroy(&dhcp6->user_class_data); if (__ni_config_parse_dhcp6_class_data_nodes(child, &dhcp6->user_class_data) < 0) { ni_string_array_destroy(&dhcp6->user_class_data); return FALSE; } if (dhcp6->user_class_data.count == 0) { ni_warn("config: discarding <user-class> without any <class-data>"); } } else if (!strcmp(child->name, "vendor-class") && (attrval = xml_node_get_attr(child, "enterprise-number")) != NULL) { char * err; long num; num = strtol(attrval, &err, 0); if (*err != '\0' || num < 0 || num >= 0xffffffff) { ni_error("config: unable to parse <vendor-class enterprise-number=\"%s\"", attrval); return FALSE; } ni_string_array_destroy(&dhcp6->vendor_class_data); if (__ni_config_parse_dhcp6_class_data_nodes(child, &dhcp6->vendor_class_data) < 0) { ni_string_array_destroy(&dhcp6->vendor_class_data); return FALSE; } if (dhcp6->vendor_class_data.count == 0) { ni_warn("config: discarding <vendor-class> without any <class-data>"); } else { dhcp6->vendor_class_en = num; } } else if (!strcmp(child->name, "vendor-opts") && (attrval = xml_node_get_attr(child, "enterprise-number")) != NULL) { char * err; long num; num = strtol(attrval, &err, 0); if (*err != '\0' || num < 0 || num >= 0xffffffff) { ni_error("config: unable to parse <vendor-class enterprise-number=\"%s\"", attrval); return FALSE; } ni_var_array_destroy(&dhcp6->vendor_opts_data); if (__ni_config_parse_dhcp6_vendor_opts_nodes(child, &dhcp6->vendor_opts_data) < 0) { ni_var_array_destroy(&dhcp6->vendor_opts_data); } if (dhcp6->vendor_opts_data.count == 0) { ni_warn("config: discarding <vendor-opts> without any <option>"); } else { dhcp6->vendor_opts_en = num; } } else if (!strcmp(child->name, "lease-time") && child->cdata) { dhcp6->lease_time = strtoul(child->cdata, NULL, 0); } else if (!strcmp(child->name, "ignore-server") && (attrval = xml_node_get_attr(child, "ip")) != NULL) { ni_string_array_append(&dhcp6->ignore_servers, attrval); } else if (!strcmp(child->name, "prefer-server")) { ni_server_preference_t *pref; const char *id, *ip; ip = xml_node_get_attr(child, "ip"); id = xml_node_get_attr(child, "id"); if (ip == NULL && id == NULL) continue; if (dhcp6->num_preferred_servers >= NI_DHCP_SERVER_PREFERENCES_MAX) { ni_warn("config: too many <prefer-server> elements"); continue; } pref = &dhcp6->preferred_server[dhcp6->num_preferred_servers++]; if (ip && ni_sockaddr_parse(&pref->address, ip, AF_INET6) < 0) { ni_error("config: unable to parse <prefer-server ip=\"%s\"", ip); return FALSE; } if (id) { int len; /* DUID is "opaque", but has 2 bytes type + up to 128 bytes */ if ((len = sizeof(pref->serverid.data)) > 130) len = 130; /* DUID-LL has 2+2 fixed bytes + variable length hwaddress * and seems to be the shortest one I'm aware of ... */ if ((len = ni_parse_hex(id, pref->serverid.data, len)) <= 4) { ni_error("config: unable to parse <prefer-server id=\"%s\"", id); return FALSE; } pref->serverid.len = (size_t)len; } pref->weight = 255; if ((attrval = xml_node_get_attr(child, "weight")) != NULL) { if (!strcmp(attrval, "always")) { pref->weight = 255; } else if (!strcmp(attrval, "never")) { pref->weight = -1; } else { pref->weight = strtol(attrval, NULL, 0); if (pref->weight > 255) { pref->weight = 255; ni_warn("preferred dhcp server weight exceeds max, " "clamping to %d", pref->weight); } } } } else if (!strcmp(child->name, "allow-update")) { ni_config_parse_update_targets(&dhcp6->allow_update, child); } } return TRUE; }