summaryrefslogtreecommitdiff
path: root/usr/src/lib/libiscsitgt/common/xml.c
diff options
context:
space:
mode:
authorahl <none@none>2006-11-15 19:25:44 -0800
committerahl <none@none>2006-11-15 19:25:44 -0800
commitf3861e1a2ceec23a5b699c24d814b7775a9e0b52 (patch)
tree3282cf1ca75a594f2a6fd971bb8bb6dd3a35cf7e /usr/src/lib/libiscsitgt/common/xml.c
parent0a44ef6d9afbfe052a7e975f55ea0d2954b62a82 (diff)
downloadillumos-gate-f3861e1a2ceec23a5b699c24d814b7775a9e0b52.tar.gz
PSARC 2006/622 iSCSI/ZFS Integration
6484731 zfs import only mounts and shares the first layer of hierarchy 6493750 zfs and iSCSI do not work togetherly correctly 6494075 destroying a pool shouldn't touch the DSL --HG-- rename : usr/src/cmd/iscsi/common/iscsi_door.h => deleted_files/usr/src/cmd/iscsi/common/iscsi_door.h rename : usr/src/cmd/iscsi/common/local_types.h => deleted_files/usr/src/cmd/iscsi/common/local_types.h rename : usr/src/cmd/iscsi/common/xml.h => usr/src/lib/libiscsitgt/common/iscsitgt_impl.h rename : usr/src/cmd/iscsi/common/xml.c => usr/src/lib/libiscsitgt/common/xml.c
Diffstat (limited to 'usr/src/lib/libiscsitgt/common/xml.c')
-rw-r--r--usr/src/lib/libiscsitgt/common/xml.c949
1 files changed, 949 insertions, 0 deletions
diff --git a/usr/src/lib/libiscsitgt/common/xml.c b/usr/src/lib/libiscsitgt/common/xml.c
new file mode 100644
index 0000000000..86aa04c7f6
--- /dev/null
+++ b/usr/src/lib/libiscsitgt/common/xml.c
@@ -0,0 +1,949 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <inttypes.h>
+#include <assert.h>
+#include <libxml/xmlreader.h>
+#include <strings.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <sys/stat.h>
+
+#include "iscsitgt_impl.h"
+
+/*
+ * Forward declarations
+ */
+static char *strip_space(char *value);
+static tgt_node_t *node_alloc();
+static void node_free(tgt_node_t *x);
+static Boolean_t node_name(tgt_node_t *x, const xmlChar *n);
+static Boolean_t node_value(tgt_node_t *x, const xmlChar *n, Boolean_t s);
+static tgt_node_t *node_parent(tgt_node_t *x);
+static tgt_node_t *node_child(tgt_node_t *x);
+static tgt_node_t *node_alloc_attr(tgt_node_t *x);
+static void buf_add_node_attr(char **b, tgt_node_t *x);
+static void buf_add_comment(char **b, char *comment);
+static void buf_add_str(char **b, char *str);
+
+#define XML_COMMENT_STR "!--"
+#define XML_COMMENT_END "--"
+
+void
+tgt_node_free(tgt_node_t *n)
+{
+ tgt_node_t *c,
+ *c1;
+ if (n == NULL)
+ return;
+ for (c = n->x_child; c; ) {
+ c1 = c->x_sibling;
+ tgt_node_free(c);
+ c = c1;
+ }
+ for (c = n->x_attr; c; ) {
+ c1 = c->x_sibling;
+ node_free(c);
+ c = c1;
+ }
+ node_free(n);
+
+}
+
+/*
+ * []----
+ * | xml_update_config -- dump out in core node tree to XML parsable file
+ * |
+ * | The depth argument is only used to pad the output with white space
+ * | for indentation. This is meant to help the readability of the file
+ * | for humans.
+ * []----
+ */
+static void
+xml_update_config(tgt_node_t *t, int depth, FILE *output)
+{
+ int i;
+ tgt_node_t *c;
+
+ if (t == NULL)
+ return;
+
+ /*
+ * If this node has an attribute which indicates it's incore only
+ * we don't dump it out to a file.
+ */
+ for (c = t->x_attr; c; c = c->x_sibling)
+ if ((strcmp(c->x_name, XML_ELEMENT_INCORE) == 0) &&
+ (strcmp(c->x_value, XML_VALUE_TRUE) == 0))
+ return;
+
+ for (i = 0; i < depth; i++)
+ (void) fprintf(output, " ");
+ if (strcmp(t->x_name, XML_COMMENT_STR) == 0) {
+ (void) fprintf(output, "<%s%s%s>\n", XML_COMMENT_STR,
+ t->x_value, XML_COMMENT_END);
+ return;
+ }
+ if ((t->x_child == NULL) && (t->x_value != NULL) &&
+ (t->x_attr == NULL) &&
+ (((depth * 4) + ((strlen(t->x_name) * 2) + 5) +
+ strlen(t->x_value)) < 80)) {
+
+ (void) fprintf(output, "<%s>%s</%s>\n", t->x_name, t->x_value,
+ t->x_name);
+
+ } else {
+ (void) fprintf(output, "<%s", t->x_name);
+ for (c = t->x_attr; c; c = c->x_sibling)
+ (void) fprintf(output, " %s='%s'", c->x_name,
+ c->x_value);
+ (void) fprintf(output, ">\n");
+ if (t->x_value) {
+ for (i = 0; i < depth + 1; i++)
+ (void) fprintf(output, " ");
+ (void) fprintf(output, "%s\n", t->x_value);
+ }
+ for (c = t->x_child; c; c = c->x_sibling)
+ xml_update_config(c, depth + 1, output);
+ for (i = 0; i < depth; i++)
+ (void) fprintf(output, " ");
+ (void) fprintf(output, "</%s>\n", t->x_name);
+ }
+}
+
+Boolean_t
+tgt_dump2file(tgt_node_t *root, char *path)
+{
+ FILE *output;
+
+ if ((output = fopen(path, "wb")) == NULL) {
+ syslog(LOG_ERR, "Cannot open the file: %s\n", path);
+ return (False);
+ } else {
+ xml_update_config(root, 0, output);
+ (void) fclose(output);
+
+ /*
+ * Make sure only root can access the file since we're
+ * optionally keeping CHAP secrets located here.
+ */
+ (void) chmod(path, 0600);
+
+ return (True);
+ }
+}
+
+/*
+ * tgt_dump2buf -- dumps node tree to buffer, allocating memory as it goes
+ *
+ * It is up to the caller, when finished with 'buf', to call free()
+ */
+void
+tgt_dump2buf(tgt_node_t *n, char **buf)
+{
+ tgt_node_t *c;
+
+ if (n == NULL)
+ return;
+ if (strcmp(n->x_name, XML_COMMENT_STR) == 0) {
+ buf_add_comment(buf, n->x_value);
+ return;
+ }
+ buf_add_node_attr(buf, n);
+ if (n->x_value != NULL)
+ tgt_buf_add_tag(buf, n->x_value, Tag_String);
+ for (c = n->x_child; c; c = c->x_sibling)
+ tgt_dump2buf(c, buf);
+ tgt_buf_add_tag(buf, n->x_name, Tag_End);
+}
+
+char *common_attr_list[] = {
+ XML_ELEMENT_NAME,
+ XML_ELEMENT_VERS,
+ XML_ELEMENT_INCORE,
+ 0
+};
+
+Boolean_t
+tgt_node_process(xmlTextReaderPtr r, tgt_node_t **node)
+{
+ const xmlChar *name,
+ *value;
+ char **ap;
+ xmlElementType node_type;
+ tgt_node_t *n,
+ *an;
+
+ n = *node;
+ if (n == NULL) {
+ n = node_alloc();
+ if (n == NULL)
+ return (False);
+ *node = n;
+ }
+
+ name = (xmlChar *)xmlTextReaderConstName(r);
+ if (name == NULL) {
+ node_free(n);
+ return (False);
+ }
+
+ node_type = (xmlElementType)xmlTextReaderNodeType(r);
+
+ value = (xmlChar *)xmlTextReaderConstValue(r);
+
+ if (node_type == XML_ELEMENT_NODE) {
+ if (n->x_state != NodeAlloc) {
+ n = node_child(n);
+ *node = n;
+ if (n == NULL)
+ return (False);
+ }
+ if (xmlTextReaderAttributeCount(r) > 0) {
+
+ for (ap = common_attr_list; *ap; ap++) {
+ value = xmlTextReaderGetAttribute(r,
+ (xmlChar *)*ap);
+
+ if (value != NULL) {
+ if ((an = node_alloc_attr(n)) == NULL)
+ return (False);
+ if (node_name(an, (xmlChar *)*ap) ==
+ False) {
+ node_free(an);
+ return (False);
+ }
+ if (node_value(an, value, True) ==
+ False) {
+ node_free(an);
+ return (False);
+ }
+ free((char *)value);
+ }
+ }
+ }
+
+ if (node_name(n, name) == False) {
+ node_free(n);
+ return (False);
+ }
+ } else if ((value != NULL) && (node_type == XML_TEXT_NODE)) {
+ if (node_value(n, value, True) == False) {
+ node_free(n);
+ return (False);
+ }
+ } else if (node_type == XML_ELEMENT_DECL) {
+ n = node_parent(n);
+ if (n == NULL)
+ return (False);
+ *node = n;
+ } else if (node_type == XML_COMMENT_NODE) {
+ n = node_child(n);
+ if (node_name(n, (xmlChar *)XML_COMMENT_STR) == False) {
+ node_free(n);
+ return (False);
+ }
+ if (node_value(n, (xmlChar *)value, False) == False) {
+ node_free(n);
+ return (False);
+ }
+ } else if (node_type != XML_DTD_NODE) {
+ node_free(n);
+ return (False);
+ }
+ return (True);
+}
+
+Boolean_t
+tgt_find_attr_str(tgt_node_t *n, char *attr, char **value)
+{
+ tgt_node_t *a;
+
+ if ((n == NULL) || (n->x_attr == NULL))
+ return (False);
+
+ for (a = n->x_attr; a; a = a->x_sibling)
+ if (strcmp(a->x_name, attr) == 0) {
+ *value = a->x_value ? strdup(a->x_value) : NULL;
+ return (True);
+ }
+ return (False);
+}
+
+Boolean_t
+tgt_find_value_str(tgt_node_t *n, char *name, char **value)
+{
+ tgt_node_t *c;
+
+ if ((n == NULL) || (n->x_name == NULL))
+ return (False);
+
+ if (strcmp(n->x_name, name) == 0) {
+ *value = n->x_value ? strdup(n->x_value) : NULL;
+ return (True);
+ }
+ for (c = n->x_child; c; c = c->x_sibling) {
+ if (tgt_find_value_str(c, name, value) == True)
+ return (True);
+ }
+ return (False);
+}
+
+Boolean_t
+tgt_find_value_int(tgt_node_t *n, char *name, int *value)
+{
+ tgt_node_t *c;
+
+ if ((n == NULL) || (n->x_name == NULL))
+ return (False);
+
+ if (strcmp(n->x_name, name) == 0) {
+ if (n->x_value == NULL)
+ return (False);
+ *value = strtol(n->x_value, NULL, 0);
+ return (True);
+ }
+ for (c = n->x_child; c; c = c->x_sibling) {
+ if (tgt_find_value_int(c, name, value) == True)
+ return (True);
+ }
+ return (False);
+}
+
+/*
+ * []----
+ * | xml_find_value_intchk -- if node exists, check to see if value is okay
+ * []----
+ */
+Boolean_t
+tgt_find_value_intchk(tgt_node_t *n, char *name, int *value)
+{
+ char *str,
+ chk[32];
+ Boolean_t rval;
+
+ if (tgt_find_value_str(n, name, &str) == True) {
+
+ *value = strtol(str, NULL, 0);
+ /*
+ * Validate that the input string hasn't overrun what
+ * what an integer can handle. This is done by simply
+ * printing out the result of the conversion into a buffer
+ * and comparing it to the incoming string. That way when
+ * someone enters 4294967296 which strtol returns as 0
+ * we'll catch it.
+ */
+ if ((str[0] == '0') && (str[1] != '\0')) {
+ if (str[1] == 'x')
+ (void) snprintf(chk, sizeof (chk), "0x%x",
+ *value);
+ else if (str[1] == 'X')
+ (void) snprintf(chk, sizeof (chk), "0X%x",
+ *value);
+ else
+ (void) snprintf(chk, sizeof (chk), "0%o",
+ *value);
+ } else
+ (void) snprintf(chk, sizeof (chk), "%d", *value);
+ if (strcmp(chk, str) == 0)
+ rval = True;
+ else
+ rval = False;
+ free(str);
+ return (rval);
+ } else
+ return (True);
+}
+
+Boolean_t
+tgt_find_value_boolean(tgt_node_t *n, char *name, Boolean_t *value)
+{
+ tgt_node_t *c;
+
+ if ((n == NULL) || (n->x_name == NULL))
+ return (False);
+
+ if (strcmp(n->x_name, name) == 0) {
+ if (n->x_value == NULL)
+ return (False);
+ *value = strcmp(n->x_value, "true") == 0 ? True : False;
+ return (True);
+ }
+ for (c = n->x_child; c; c = c->x_sibling) {
+ if (tgt_find_value_boolean(c, name, value) == True)
+ return (True);
+ }
+ return (False);
+}
+
+tgt_node_t *
+tgt_node_next(tgt_node_t *n, char *name, tgt_node_t *cur)
+{
+ tgt_node_t *x,
+ *p;
+
+ if (n == NULL)
+ return (NULL);
+
+ if (cur != NULL) {
+ for (x = cur->x_sibling; x; x = x->x_sibling)
+ if (strcmp(x->x_name, name) == 0)
+ return (x);
+ return (NULL);
+ }
+
+ if (n->x_name == NULL)
+ return (NULL);
+
+ if (strcmp(n->x_name, name) == 0)
+ return (n);
+ for (x = n->x_child; x; x = x->x_sibling)
+ if ((p = tgt_node_next(x, name, 0)) != NULL)
+ return (p);
+ return (NULL);
+}
+
+tgt_node_t *
+tgt_node_next_child(tgt_node_t *n, char *name, tgt_node_t *cur)
+{
+ if (cur != NULL) {
+ n = cur->x_sibling;
+ } else {
+ if (n != NULL)
+ n = n->x_child;
+ else
+ return (NULL);
+ }
+ while (n) {
+ if (strcmp(n->x_name, name) == 0)
+ return (n);
+ n = n->x_sibling;
+ }
+ return (NULL);
+}
+
+void
+tgt_node_add(tgt_node_t *p, tgt_node_t *c)
+{
+ if ((p == NULL) || (c == NULL))
+ return;
+
+ if (p->x_child == NULL)
+ p->x_child = c;
+ else {
+ c->x_sibling = p->x_child;
+ p->x_child = c;
+ }
+}
+
+void
+tgt_node_add_attr(tgt_node_t *p, tgt_node_t *a)
+{
+ if ((p == NULL) || (a == NULL))
+ return;
+
+ if (p->x_attr == NULL)
+ p->x_attr = a;
+ else {
+ a->x_sibling = p->x_attr;
+ p->x_attr = a;
+ }
+}
+
+tgt_node_t *
+tgt_node_alloc(char *name, xml_val_type_t type, void *value)
+{
+ tgt_node_t *d = node_alloc();
+ int value_len = 0;
+ char *value_str = NULL;
+
+ if (d == NULL)
+ return (NULL);
+ switch (type) {
+ case String:
+ if (value)
+ value_len = strlen((char *)value) + 1;
+ break;
+ case Int:
+ value_len = sizeof (int) * 2 + 3;
+ break;
+ case Uint64:
+ value_len = sizeof (uint64_t) * 2 + 3;
+ break;
+ }
+ if (value_len &&
+ (value_str = (char *)calloc(sizeof (char), value_len)) == NULL)
+ return (NULL);
+ if (node_name(d, (xmlChar *)name) == False) {
+ free(value_str);
+ return (NULL);
+ }
+ if (value_str) {
+ switch (type) {
+ case String:
+ (void) snprintf(value_str, value_len, "%s",
+ (char *)value);
+ break;
+ case Int:
+ (void) snprintf(value_str, value_len, "0x%x",
+ *(int *)value);
+ break;
+ case Uint64:
+ (void) snprintf(value_str, value_len, "0x%llx",
+ *(uint64_t *)value);
+ break;
+ }
+ }
+ (void) node_value(d, (xmlChar *)value_str, True);
+
+ return (d);
+}
+
+Boolean_t
+tgt_xml_encode(uint8_t *ip, size_t ip_size, char **buf, size_t *buf_size)
+{
+ char *bp;
+ *buf_size = (ip_size * 2) + 1;
+
+ if ((*buf = (char *)malloc(*buf_size)) == NULL) {
+ *buf_size = 0;
+ return (False);
+ }
+
+ for (bp = *buf; ip_size; ip_size--) {
+ (void) sprintf(bp, "%.2x", *ip);
+ ip++;
+ bp += 2;
+ }
+
+ return (True);
+}
+
+Boolean_t
+tgt_xml_decode(char *buf, uint8_t **ip, size_t *ip_size)
+{
+ uint8_t *i;
+ size_t buf_size = strlen(buf);
+ *ip_size = buf_size / 2;
+
+ if ((*ip = (uint8_t *)malloc(*ip_size)) == NULL) {
+ *ip_size = 0;
+ return (False);
+ }
+
+ for (i = *ip; buf_size; buf_size -= 2) {
+ char x[3];
+ bcopy(buf, x, 2);
+ x[2] = 0;
+ *i++ = strtol(x, NULL, 16);
+ buf += 2;
+ }
+ return (True);
+}
+
+Boolean_t
+tgt_node_remove(tgt_node_t *parent, tgt_node_t *child, match_type_t m)
+{
+ tgt_node_t *s,
+ *c = NULL;
+
+ if ((parent == NULL) || (child == NULL))
+ return (False);
+
+ for (s = parent->x_child; s; c = s, s = s->x_sibling) {
+
+ /*
+ * See if the new child node matches one of the children
+ * in the parent.
+ */
+ if ((strcmp(s->x_name, child->x_name) == 0) &&
+ ((m == MatchName) || (strcmp(s->x_value,
+ child->x_value) == 0))) {
+
+ if (parent->x_child == s) {
+ parent->x_child = s->x_sibling;
+ } else {
+ c->x_sibling = s->x_sibling;
+ }
+ tgt_node_free(s);
+ break;
+ }
+ }
+ if (s == NULL)
+ return (False);
+ else
+ return (True);
+}
+
+void
+tgt_node_replace(tgt_node_t *parent, tgt_node_t *child, match_type_t m)
+{
+ tgt_node_t *s,
+ *c;
+
+ if ((parent == NULL) || (child == NULL))
+ return;
+
+ for (s = parent->x_child; s; s = s->x_sibling) {
+
+ /*
+ * See if the new child node matches one of the children
+ * in the parent.
+ */
+ if ((strcmp(s->x_name, child->x_name) == 0) &&
+ ((m == MatchName) || (strcmp(s->x_value,
+ child->x_value) == 0))) {
+
+ /*
+ * We have a match. Now save the values of the new
+ * child in this current node.
+ */
+ free(s->x_name);
+ free(s->x_value);
+ s->x_name = strdup(child->x_name);
+ s->x_value = strdup(child->x_value);
+ if (s->x_child) {
+ tgt_node_free(s->x_child);
+ s->x_child = NULL;
+ }
+ for (c = child->x_child; c; c = c->x_sibling)
+ (void) tgt_node_add(s, tgt_node_dup(c));
+ break;
+ }
+ }
+
+ if (s == NULL) {
+ /*
+ * Never found the child so add it
+ */
+ (void) tgt_node_add(parent, tgt_node_dup(child));
+ }
+}
+
+Boolean_t
+tgt_update_value_str(tgt_node_t *node, char *name, char *str)
+{
+ if ((node == NULL) || (strcmp(name, node->x_name) != 0))
+ return (False);
+ if (node->x_value != NULL)
+ free(node->x_value);
+ node->x_value = strdup(str);
+ node->x_state = NodeValue;
+ return (True);
+}
+
+tgt_node_t *
+tgt_node_find(tgt_node_t *n, char *name)
+{
+ tgt_node_t *rval;
+
+ for (rval = n->x_child; rval; rval = rval->x_sibling)
+ if (strcmp(rval->x_name, name) == 0)
+ break;
+ return (rval);
+}
+
+tgt_node_t *
+tgt_node_dup(tgt_node_t *n)
+{
+ tgt_node_t *d = node_alloc(),
+ *c;
+
+ if (d == NULL)
+ return (NULL);
+ if (node_name(d, (xmlChar *)n->x_name) == False)
+ return (NULL);
+ if (node_value(d, (xmlChar *)n->x_value, True) == False)
+ return (NULL);
+ for (c = n->x_child; c; c = c->x_sibling)
+ (void) tgt_node_add(d, tgt_node_dup(c));
+ return (d);
+}
+
+void
+tgt_buf_add(char **b, char *element, const char *cdata)
+{
+ tgt_buf_add_tag(b, element, Tag_Start);
+ if (cdata != NULL)
+ tgt_buf_add_tag(b, cdata, Tag_String);
+ tgt_buf_add_tag(b, element, Tag_End);
+}
+
+/*
+ * []----
+ * | tgt_buf_add_tag -- adds string to buffer allocating space, sets up tags too
+ * |
+ * | Helper function to build a string by allocating memory as we go.
+ * | If the string argument 'str' is defined to be a start or end tag
+ * | as declared by 'type' argument add the appropriate characters.
+ * []----
+ */
+void
+tgt_buf_add_tag(char **b, const char *str, val_type_t type)
+{
+ char *buf;
+ int len;
+
+ /*
+ * We will add potentially up to 3 extra characters plus the NULL byte
+ */
+ len = strlen(str) + 4;
+ if ((buf = malloc(len)) == NULL)
+ return;
+
+ (void) snprintf(buf, len, "%s%s%s%s", type == Tag_String ? "" : "<",
+ type == Tag_End ? "/" : "", str, type == Tag_String ? "" : ">");
+ buf_add_str(b, buf);
+ free(buf);
+}
+
+/*
+ * []----
+ * | tgt_buf_add_tag_and_attr -- variant on tgt_buf_add_tag which also gives
+ * | attr
+ * []----
+ */
+void
+tgt_buf_add_tag_and_attr(char **b, char *str, char *attr)
+{
+ char *buf;
+ int len;
+
+ /*
+ * In addition to the 'str' and 'attr' strings the code will add
+ * three characters plus a null byte.
+ */
+ len = strlen(str) + strlen(attr) + 4;
+ if ((buf = malloc(len)) == NULL)
+ return;
+
+ (void) snprintf(buf, len, "<%s %s>", str, attr);
+ buf_add_str(b, buf);
+ free(buf);
+}
+
+/*
+ * []----
+ * | Utility functions
+ * []----
+ */
+static tgt_node_t *
+node_alloc()
+{
+ tgt_node_t *x = (tgt_node_t *)calloc(sizeof (tgt_node_t), 1);
+
+ if (x == NULL)
+ return (NULL);
+
+ x->x_state = NodeAlloc;
+ return (x);
+}
+
+static void
+node_free(tgt_node_t *x)
+{
+ x->x_state = NodeFree;
+ if (x->x_name)
+ free(x->x_name);
+ if (x->x_value)
+ free(x->x_value);
+ free(x);
+}
+
+static Boolean_t
+node_name(tgt_node_t *x, const xmlChar *n)
+{
+ assert(x->x_state == NodeAlloc);
+ if ((n == NULL) || (strlen((char *)n) == 0))
+ return (False);
+
+ x->x_state = NodeName;
+ x->x_name = strip_space((char *)n);
+ return (True);
+}
+
+static Boolean_t
+node_value(tgt_node_t *x, const xmlChar *n, Boolean_t do_strip)
+{
+ assert(x->x_state == NodeName);
+ if ((n == NULL) || (strlen((char *)n) == NULL))
+ return (False);
+
+ x->x_state = NodeValue;
+ x->x_value = (do_strip == True) ?
+ strip_space((char *)n) : strdup((char *)n);
+ return (True);
+}
+
+static tgt_node_t *
+node_parent(tgt_node_t *x)
+{
+ return (x->x_parent);
+}
+
+static tgt_node_t *
+node_child(tgt_node_t *x)
+{
+ tgt_node_t *n;
+
+ if ((n = node_alloc()) == NULL)
+ return (NULL);
+
+ if (x->x_child == NULL) {
+ x->x_child = n;
+ } else {
+ n->x_sibling = x->x_child;
+ x->x_child = n;
+ }
+ n->x_parent = x;
+ return (n);
+}
+
+static tgt_node_t *
+node_alloc_attr(tgt_node_t *x)
+{
+ tgt_node_t *n,
+ *next;
+
+ n = node_alloc();
+ if (x->x_attr == NULL) {
+ x->x_attr = n;
+ } else {
+ for (next = x->x_attr; next->x_sibling; next = next->x_sibling)
+ ;
+ next->x_sibling = n;
+ }
+ if (n != NULL)
+ n->x_parent = x;
+ return (n);
+}
+
+static void
+buf_add_str(char **b, char *str)
+{
+ int len,
+ olen = 0;
+ char *p = *b;
+
+ /*
+ * Make sure we have enough room for the string and tag characters
+ * plus a NULL byte.
+ */
+ if (str == NULL)
+ return;
+
+ len = strlen(str) + 1;
+ if (p == NULL) {
+ if ((p = malloc(len)) == NULL)
+ return;
+ } else {
+ olen = strlen(p);
+ p = realloc(p, olen + len);
+ }
+ (void) strncpy(p + olen, str, len);
+ *b = p;
+}
+
+static void
+buf_add_node_attr(char **b, tgt_node_t *x)
+{
+ char *buf;
+ tgt_node_t *n;
+ int len;
+
+ /* ---- null byte and starting '<' character ---- */
+ len = strlen(x->x_name) + 2;
+ if ((buf = malloc(len)) == NULL)
+ return;
+ (void) snprintf(buf, len, "<%s", x->x_name);
+ buf_add_str(b, buf);
+ free(buf);
+
+ for (n = x->x_attr; n; n = n->x_sibling) {
+ len = strlen(n->x_name) + strlen(n->x_value) + 5;
+ if ((buf = malloc(len)) == NULL)
+ return;
+ (void) snprintf(buf, len, " %s='%s'", n->x_name, n->x_value);
+ buf_add_str(b, buf);
+ free(buf);
+ }
+ buf_add_str(b, ">");
+}
+
+static void
+buf_add_comment(char **b, char *comment)
+{
+ char *p = *b;
+ int len,
+ olen;
+
+ if (comment == NULL)
+ return;
+
+ /*
+ * Room for the strings, plus the brackets and NULL byte
+ */
+ len = strlen(comment) + strlen(XML_COMMENT_STR) +
+ strlen(XML_COMMENT_END) + 3;
+
+ if (p == NULL)
+ p = malloc(len);
+ else {
+ olen = strlen(p);
+ p = realloc(p, olen + len);
+ }
+ (void) snprintf(p + olen, len, "<%s%s%s>", XML_COMMENT_STR, comment,
+ XML_COMMENT_END);
+ *b = p;
+}
+
+static char *
+strip_space(char *value)
+{
+ char *p,
+ *n;
+
+ for (p = value; p && *p; p++)
+ if (!isspace(*p))
+ break;
+ if ((p == NULL) || (*p == '\0'))
+ return (NULL);
+
+ p = strdup(p);
+ for (n = (p + strlen(p) - 1); n >= p; n--)
+ if (!isspace(*n)) {
+ n++;
+ break;
+ }
+ *n = '\0';
+ return (p);
+}