Home | History | Annotate | Download | only in common
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 #include <stdio.h>
     27 #include <unistd.h>
     28 #include <sys/types.h>
     29 #include <inttypes.h>
     30 #include <assert.h>
     31 #include <libxml/xmlreader.h>
     32 #include <strings.h>
     33 #include <ctype.h>
     34 #include <stdlib.h>
     35 #include <syslog.h>
     36 #include <sys/stat.h>
     37 
     38 #include "iscsitgt_impl.h"
     39 
     40 /*
     41  * Forward declarations
     42  */
     43 static char *strip_space(char *value);
     44 static tgt_node_t *node_alloc();
     45 static void node_free(tgt_node_t *x);
     46 static Boolean_t node_name(tgt_node_t *x, const xmlChar *n);
     47 static Boolean_t node_value(tgt_node_t *x, const xmlChar *n, Boolean_t s);
     48 static tgt_node_t *node_parent(tgt_node_t *x);
     49 static tgt_node_t *node_child(tgt_node_t *x);
     50 static tgt_node_t *node_alloc_attr(tgt_node_t *x);
     51 static void buf_add_node_attr(char **b, tgt_node_t *x);
     52 static void buf_add_comment(char **b, char *comment);
     53 static void buf_add_str(char **b, char *str);
     54 
     55 #define	XML_COMMENT_STR	"!--"
     56 #define	XML_COMMENT_END "--"
     57 
     58 void
     59 tgt_node_free(tgt_node_t *n)
     60 {
     61 	tgt_node_t	*c;
     62 	tgt_node_t	*c1;
     63 
     64 	if (n == NULL)
     65 		return;
     66 	for (c = n->x_child; c; ) {
     67 		c1 = c->x_sibling;
     68 		tgt_node_free(c);
     69 		c = c1;
     70 	}
     71 	for (c = n->x_attr; c; ) {
     72 		c1 = c->x_sibling;
     73 		node_free(c);
     74 		c = c1;
     75 	}
     76 	node_free(n);
     77 
     78 }
     79 
     80 /*
     81  * tgt_dump2buf -- dumps node tree to buffer, allocating memory as it goes
     82  *
     83  * It is up to the caller, when finished with 'buf', to call free()
     84  */
     85 void
     86 tgt_dump2buf(tgt_node_t *n, char **buf)
     87 {
     88 	tgt_node_t	*c;
     89 
     90 	if (n == NULL)
     91 		return;
     92 	if (strcmp(n->x_name, XML_COMMENT_STR) == 0) {
     93 		buf_add_comment(buf, n->x_value);
     94 		return;
     95 	}
     96 	buf_add_node_attr(buf, n);
     97 	if (n->x_value != NULL)
     98 		tgt_buf_add_tag(buf, n->x_value, Tag_String);
     99 	for (c = n->x_child; c; c = c->x_sibling)
    100 		tgt_dump2buf(c, buf);
    101 	tgt_buf_add_tag(buf, n->x_name, Tag_End);
    102 }
    103 
    104 char *common_attr_list[] = {
    105 	XML_ELEMENT_NAME,
    106 	XML_ELEMENT_VERS,
    107 	XML_ELEMENT_INCORE,
    108 	0
    109 };
    110 
    111 Boolean_t
    112 tgt_node_process(xmlTextReaderPtr r, tgt_node_t **node)
    113 {
    114 	const xmlChar	*name;
    115 	const xmlChar	*value;
    116 	char		**ap;
    117 	xmlElementType	node_type;
    118 	tgt_node_t	*n;
    119 	tgt_node_t	*an;
    120 
    121 	n = *node;
    122 	if (n == NULL) {
    123 		n = node_alloc();
    124 		if (n == NULL)
    125 			return (False);
    126 		*node = n;
    127 	}
    128 
    129 	name = (xmlChar *)xmlTextReaderConstName(r);
    130 	if (name == NULL) {
    131 		node_free(n);
    132 		*node = NULL;
    133 		return (False);
    134 	}
    135 
    136 	node_type = (xmlElementType)xmlTextReaderNodeType(r);
    137 
    138 	value = (xmlChar *)xmlTextReaderConstValue(r);
    139 
    140 	if (node_type == XML_ELEMENT_NODE) {
    141 		if (n->x_state != NodeAlloc) {
    142 			n = node_child(n);
    143 			*node = n;
    144 			if (n == NULL)
    145 				return (False);
    146 		}
    147 		if (xmlTextReaderAttributeCount(r) > 0) {
    148 
    149 			for (ap = common_attr_list; *ap; ap++) {
    150 				value = xmlTextReaderGetAttribute(r,
    151 				    (xmlChar *)*ap);
    152 
    153 				if (value != NULL) {
    154 					if ((an = node_alloc_attr(n)) == NULL)
    155 						return (False);
    156 					if (node_name(an, (xmlChar *)*ap) ==
    157 					    False) {
    158 						node_free(an);
    159 						return (False);
    160 					}
    161 					if (node_value(an, value, True) ==
    162 					    False) {
    163 						node_free(an);
    164 						return (False);
    165 					}
    166 					free((char *)value);
    167 				}
    168 			}
    169 		}
    170 
    171 		if (node_name(n, name) == False) {
    172 			node_free(n);
    173 			*node = NULL;
    174 			return (False);
    175 		}
    176 	} else if ((value != NULL) && (node_type == XML_TEXT_NODE)) {
    177 		if (node_value(n, value, True) == False) {
    178 			node_free(n);
    179 			*node = NULL;
    180 			return (False);
    181 		}
    182 	} else if (node_type == XML_ELEMENT_DECL) {
    183 		n = node_parent(n);
    184 		if (n == NULL)
    185 			return (False);
    186 		*node = n;
    187 	} else if (node_type == XML_COMMENT_NODE) {
    188 		n = node_child(n);
    189 		if (node_name(n, (xmlChar *)XML_COMMENT_STR) == False) {
    190 			node_free(n);
    191 			*node = NULL;
    192 			return (False);
    193 		}
    194 		if (node_value(n, (xmlChar *)value, False) == False) {
    195 			node_free(n);
    196 			*node = NULL;
    197 			return (False);
    198 		}
    199 	} else if (node_type != XML_DTD_NODE) {
    200 		node_free(n);
    201 		*node = NULL;
    202 		return (False);
    203 	}
    204 	return (True);
    205 }
    206 
    207 Boolean_t
    208 tgt_find_attr_str(tgt_node_t *n, char *attr, char **value)
    209 {
    210 	tgt_node_t	*a;
    211 
    212 	if ((n == NULL) || (n->x_attr == NULL))
    213 		return (False);
    214 
    215 	for (a = n->x_attr; a; a = a->x_sibling)
    216 		if (strcmp(a->x_name, attr) == 0) {
    217 			*value = a->x_value ? strdup(a->x_value) : NULL;
    218 			return (True);
    219 		}
    220 	return (False);
    221 }
    222 
    223 Boolean_t
    224 tgt_find_value_str(tgt_node_t *n, char *name, char **value)
    225 {
    226 	tgt_node_t	*c;
    227 
    228 	if ((n == NULL) || (n->x_name == NULL))
    229 		return (False);
    230 
    231 	if (strcmp(n->x_name, name) == 0) {
    232 		*value = n->x_value ? strdup(n->x_value) : NULL;
    233 		return (True);
    234 	}
    235 	for (c = n->x_child; c; c = c->x_sibling) {
    236 		if (tgt_find_value_str(c, name, value) == True)
    237 			return (True);
    238 	}
    239 	return (False);
    240 }
    241 
    242 Boolean_t
    243 tgt_find_value_int(tgt_node_t *n, char *name, int *value)
    244 {
    245 	tgt_node_t	*c;
    246 
    247 	if ((n == NULL) || (n->x_name == NULL))
    248 		return (False);
    249 
    250 	if (strcmp(n->x_name, name) == 0) {
    251 		if (n->x_value == NULL)
    252 			return (False);
    253 		*value = strtol(n->x_value, NULL, 0);
    254 		return (True);
    255 	}
    256 	for (c = n->x_child; c; c = c->x_sibling) {
    257 		if (tgt_find_value_int(c, name, value) == True)
    258 			return (True);
    259 	}
    260 	return (False);
    261 }
    262 
    263 /*
    264  * []----
    265  * | xml_find_value_intchk -- if node exists, check to see if value is okay
    266  * []----
    267  */
    268 Boolean_t
    269 tgt_find_value_intchk(tgt_node_t *n, char *name, int *value)
    270 {
    271 	char		*str;
    272 	char		chk[32];
    273 	Boolean_t	rval;
    274 
    275 	if (tgt_find_value_str(n, name, &str) == True) {
    276 
    277 		*value = strtol(str, NULL, 0);
    278 		/*
    279 		 * Validate that the input string hasn't overrun what
    280 		 * what an integer can handle. This is done by simply
    281 		 * printing out the result of the conversion into a buffer
    282 		 * and comparing it to the incoming string. That way when
    283 		 * someone enters 4294967296 which strtol returns as 0
    284 		 * we'll catch it.
    285 		 */
    286 		if ((str[0] == '0') && (str[1] != '\0')) {
    287 			if (str[1] == 'x')
    288 				(void) snprintf(chk, sizeof (chk), "0x%x",
    289 				    *value);
    290 			else if (str[1] == 'X')
    291 				(void) snprintf(chk, sizeof (chk), "0X%x",
    292 				    *value);
    293 			else
    294 				(void) snprintf(chk, sizeof (chk), "0%o",
    295 				    *value);
    296 		} else
    297 			(void) snprintf(chk, sizeof (chk), "%d", *value);
    298 		if (strcmp(chk, str) == 0)
    299 			rval = True;
    300 		else
    301 			rval = False;
    302 		free(str);
    303 		return (rval);
    304 	} else
    305 		return (True);
    306 }
    307 
    308 Boolean_t
    309 tgt_find_value_boolean(tgt_node_t *n, char *name, Boolean_t *value)
    310 {
    311 	tgt_node_t	*c;
    312 
    313 	if ((n == NULL) || (n->x_name == NULL))
    314 		return (False);
    315 
    316 	if (strcmp(n->x_name, name) == 0) {
    317 		if (n->x_value == NULL)
    318 			return (False);
    319 		*value = strcmp(n->x_value, "true") == 0 ? True : False;
    320 		return (True);
    321 	}
    322 	for (c = n->x_child; c; c = c->x_sibling) {
    323 		if (tgt_find_value_boolean(c, name, value) == True)
    324 			return (True);
    325 	}
    326 	return (False);
    327 }
    328 
    329 tgt_node_t *
    330 tgt_node_next(tgt_node_t *n, char *name, tgt_node_t *cur)
    331 {
    332 	tgt_node_t	*x;
    333 	tgt_node_t	*p;
    334 
    335 	if (n == NULL)
    336 		return (NULL);
    337 
    338 	if (cur != NULL) {
    339 		for (x = cur->x_sibling; x; x = x->x_sibling)
    340 			if (strcmp(x->x_name, name) == 0)
    341 				return (x);
    342 		return (NULL);
    343 	}
    344 
    345 	if (n->x_name == NULL)
    346 		return (NULL);
    347 
    348 	if (strcmp(n->x_name, name) == 0)
    349 		return (n);
    350 	for (x = n->x_child; x; x = x->x_sibling)
    351 		if ((p = tgt_node_next(x, name, 0)) != NULL)
    352 			return (p);
    353 	return (NULL);
    354 }
    355 
    356 tgt_node_t *
    357 tgt_node_next_child(tgt_node_t *n, char *name, tgt_node_t *cur)
    358 {
    359 	if (cur != NULL) {
    360 		n = cur->x_sibling;
    361 	} else {
    362 		if (n != NULL)
    363 			n = n->x_child;
    364 		else
    365 			return (NULL);
    366 	}
    367 	while (n) {
    368 		if (strcmp(n->x_name, name) == 0)
    369 			return (n);
    370 		n = n->x_sibling;
    371 	}
    372 	return (NULL);
    373 }
    374 
    375 void
    376 tgt_node_add(tgt_node_t *p, tgt_node_t *c)
    377 {
    378 	if ((p == NULL) || (c == NULL))
    379 		return;
    380 
    381 	c->x_parent = p;
    382 	if (p->x_child == NULL)
    383 		p->x_child = c;
    384 	else {
    385 		c->x_sibling = p->x_child;
    386 		p->x_child = c;
    387 	}
    388 }
    389 
    390 void
    391 tgt_node_add_attr(tgt_node_t *p, tgt_node_t *a)
    392 {
    393 	if ((p == NULL) || (a == NULL))
    394 		return;
    395 
    396 	if (p->x_attr == NULL)
    397 		p->x_attr = a;
    398 	else {
    399 		a->x_sibling = p->x_attr;
    400 		p->x_attr = a;
    401 	}
    402 }
    403 
    404 tgt_node_t *
    405 tgt_node_alloc(char *name, xml_val_type_t type, void *value)
    406 {
    407 	tgt_node_t	*d		= node_alloc();
    408 	int		value_len	= 0;
    409 	char		*value_str	= NULL;
    410 
    411 	if (d == NULL)
    412 		return (NULL);
    413 	switch (type) {
    414 	case String:
    415 		if (value)
    416 			value_len = strlen((char *)value) + 1;
    417 		break;
    418 	case Int:
    419 		value_len = sizeof (int) * 2 + 3;
    420 		break;
    421 	case Uint64:
    422 		value_len = sizeof (uint64_t) * 2 + 3;
    423 		break;
    424 	}
    425 	if (value_len &&
    426 	    (value_str = (char *)calloc(sizeof (char), value_len)) == NULL)
    427 		return (NULL);
    428 	if (node_name(d, (xmlChar *)name) == False) {
    429 		free(value_str);
    430 		return (NULL);
    431 	}
    432 	if (value_str) {
    433 		switch (type) {
    434 		case String:
    435 			(void) snprintf(value_str, value_len, "%s",
    436 			    (char *)value);
    437 			break;
    438 		case Int:
    439 			(void) snprintf(value_str, value_len, "%d",
    440 			    *(int *)value);
    441 			break;
    442 		case Uint64:
    443 			(void) snprintf(value_str, value_len, "0x%llx",
    444 			    *(uint64_t *)value);
    445 			break;
    446 		}
    447 	}
    448 	(void) node_value(d, (xmlChar *)value_str, True);
    449 	free(value_str);
    450 
    451 	return (d);
    452 }
    453 
    454 Boolean_t
    455 tgt_xml_encode(uint8_t *ip, size_t ip_size, char **buf, size_t *buf_size)
    456 {
    457 	char *bp;
    458 	*buf_size = (ip_size * 2) + 1;
    459 
    460 	if ((*buf = (char *)malloc(*buf_size)) == NULL) {
    461 		*buf_size = 0;
    462 		return (False);
    463 	}
    464 
    465 	for (bp = *buf; ip_size; ip_size--) {
    466 		(void) sprintf(bp, "%.2x", *ip);
    467 		ip++;
    468 		bp += 2;
    469 	}
    470 
    471 	/* make it null terminated */
    472 	*bp = 0;
    473 
    474 	return (True);
    475 }
    476 
    477 Boolean_t
    478 tgt_xml_decode(char *buf, uint8_t **ip, size_t *ip_size)
    479 {
    480 	uint8_t *i;
    481 	size_t buf_size = strlen(buf);
    482 	*ip_size = buf_size / 2;
    483 
    484 	if ((*ip = (uint8_t *)malloc(*ip_size)) == NULL) {
    485 		*ip_size = 0;
    486 		return (False);
    487 	}
    488 
    489 	for (i = *ip; buf_size; buf_size -= 2) {
    490 		char x[3];
    491 		bcopy(buf, x, 2);
    492 		x[2] = 0;
    493 		*i++ = strtol(x, NULL, 16);
    494 		buf += 2;
    495 	}
    496 	return (True);
    497 }
    498 
    499 Boolean_t
    500 tgt_node_remove(tgt_node_t *parent, tgt_node_t *child, match_type_t m)
    501 {
    502 	tgt_node_t	*s;
    503 	tgt_node_t	*c	= NULL;
    504 
    505 	if ((parent == NULL) || (child == NULL))
    506 		return (False);
    507 
    508 	for (s = parent->x_child; s; c = s, s = s->x_sibling) {
    509 
    510 		/*
    511 		 * See if the new child node matches one of the children
    512 		 * in the parent.
    513 		 */
    514 		if ((strcmp(s->x_name, child->x_name) == 0) &&
    515 		    ((m == MatchName) || (strcmp(s->x_value,
    516 		    child->x_value) == 0))) {
    517 
    518 			if (parent->x_child == s) {
    519 				parent->x_child = s->x_sibling;
    520 			} else {
    521 				c->x_sibling = s->x_sibling;
    522 			}
    523 			tgt_node_free(s);
    524 			break;
    525 		}
    526 	}
    527 	if (s == NULL)
    528 		return (False);
    529 	else
    530 		return (True);
    531 }
    532 
    533 void
    534 tgt_node_replace(tgt_node_t *parent, tgt_node_t *child, match_type_t m)
    535 {
    536 	tgt_node_t	*s;
    537 	tgt_node_t	*c;
    538 
    539 	if ((parent == NULL) || (child == NULL))
    540 		return;
    541 
    542 	for (s = parent->x_child; s; s = s->x_sibling) {
    543 
    544 		/*
    545 		 * See if the new child node matches one of the children
    546 		 * in the parent.
    547 		 */
    548 		if ((strcmp(s->x_name, child->x_name) == 0) &&
    549 		    ((m == MatchName) || (strcmp(s->x_value,
    550 		    child->x_value) == 0))) {
    551 
    552 			/*
    553 			 * We have a match. Now save the values of the new
    554 			 * child in this current node.
    555 			 */
    556 			free(s->x_name);
    557 			free(s->x_value);
    558 			s->x_name	= strdup(child->x_name);
    559 			s->x_value	= strdup(child->x_value);
    560 			if (s->x_child) {
    561 				tgt_node_free(s->x_child);
    562 				s->x_child = NULL;
    563 			}
    564 			for (c = child->x_child; c; c = c->x_sibling)
    565 				(void) tgt_node_add(s, tgt_node_dup(c));
    566 			break;
    567 		}
    568 	}
    569 
    570 	if (s == NULL) {
    571 		/*
    572 		 * Never found the child so add it
    573 		 */
    574 		(void) tgt_node_add(parent, tgt_node_dup(child));
    575 	}
    576 }
    577 
    578 Boolean_t
    579 tgt_update_value_str(tgt_node_t *node, char *name, char *str)
    580 {
    581 	if ((node == NULL) || (strcmp(name, node->x_name) != 0))
    582 		return (False);
    583 	if (node->x_value != NULL)
    584 		free(node->x_value);
    585 	node->x_value = strdup(str);
    586 	node->x_state = NodeValue;
    587 	return (True);
    588 }
    589 
    590 tgt_node_t *
    591 tgt_node_find(tgt_node_t *n, char *name)
    592 {
    593 	tgt_node_t	*rval;
    594 
    595 	for (rval = n->x_child; rval; rval = rval->x_sibling)
    596 		if (strcmp(rval->x_name, name) == 0)
    597 			break;
    598 	return (rval);
    599 }
    600 
    601 tgt_node_t *
    602 tgt_node_dup(tgt_node_t *n)
    603 {
    604 	tgt_node_t	*d = node_alloc();
    605 	tgt_node_t	*c;
    606 
    607 	if (d == NULL)
    608 		return (NULL);
    609 	if (node_name(d, (xmlChar *)n->x_name) == False)
    610 		return (NULL);
    611 	if (n->x_value && (node_value(d, (xmlChar *)n->x_value, True) == False))
    612 		return (NULL);
    613 	for (c = n->x_child; c; c = c->x_sibling)
    614 		(void) tgt_node_add(d, tgt_node_dup(c));
    615 	for (c = n->x_attr; c; c = c->x_sibling)
    616 		(void) tgt_node_add_attr(d, tgt_node_dup(c));
    617 	return (d);
    618 }
    619 
    620 #define	MAX_REPLACEMENT_ENTITY	8
    621 #define	MAX_REPLACEMENT_BUFFER	1024
    622 void
    623 tgt_buf_add(char **b, char *element, const char *cdata)
    624 {
    625 	char	entity[MAX_REPLACEMENT_ENTITY];
    626 	char	buf[MAX_REPLACEMENT_BUFFER];
    627 	int	len, i;
    628 
    629 	bzero(buf, sizeof (buf));
    630 
    631 	tgt_buf_add_tag(b, element, Tag_Start);
    632 	/*
    633 	 * we have to transform the predefined xml entities;
    634 	 */
    635 	if (cdata != NULL) {
    636 		len = strlen(cdata);
    637 		for (i = 0; i < len; i++) {
    638 			switch (cdata[i]) {
    639 			case '&':
    640 				(void) strcpy(entity, "&amp;");
    641 				break;
    642 			case '<':
    643 				(void) strcpy(entity, "&lt;");
    644 				break;
    645 			case '>':
    646 				(void) strcpy(entity, "&gt;");
    647 				break;
    648 			case '\'':
    649 				(void) strcpy(entity, "&apos;");
    650 				break;
    651 			case '"':
    652 				(void) strcpy(entity, "&quot;");
    653 				break;
    654 			default:
    655 				entity[0] = cdata[i];
    656 				entity[1] = '\0';
    657 				break;
    658 			}
    659 			(void) strlcat(buf, entity, sizeof (buf));
    660 		}
    661 		tgt_buf_add_tag(b, buf, Tag_String);
    662 	}
    663 	tgt_buf_add_tag(b, element, Tag_End);
    664 }
    665 
    666 /*
    667  * []----
    668  * | tgt_buf_add_tag -- adds string to buffer allocating space, sets up tags too
    669  * |
    670  * | Helper function to build a string by allocating memory as we go.
    671  * | If the string argument 'str' is defined to be a start or end tag
    672  * | as declared by 'type' argument add the appropriate characters.
    673  * []----
    674  */
    675 void
    676 tgt_buf_add_tag(char **b, const char *str, val_type_t type)
    677 {
    678 	char	*buf;
    679 	int	len;
    680 
    681 	/*
    682 	 * We will add potentially up to 3 extra characters plus the NULL byte
    683 	 */
    684 	len = strlen(str) + 4;
    685 	if ((buf = malloc(len)) == NULL)
    686 		return;
    687 
    688 	(void) snprintf(buf, len, "%s%s%s%s", type == Tag_String ? "" : "<",
    689 	    type == Tag_End ? "/" : "", str, type == Tag_String ? "" : ">");
    690 	buf_add_str(b, buf);
    691 	free(buf);
    692 }
    693 
    694 /*
    695  * []----
    696  * | tgt_buf_add_tag_and_attr -- variant on tgt_buf_add_tag which also gives
    697  * |    attr
    698  * []----
    699  */
    700 void
    701 tgt_buf_add_tag_and_attr(char **b, char *str, char *attr)
    702 {
    703 	char	*buf;
    704 	int	len;
    705 
    706 	/*
    707 	 * In addition to the 'str' and 'attr' strings the code will add
    708 	 * three characters plus a null byte.
    709 	 */
    710 	len = strlen(str) + strlen(attr) + 4;
    711 	if ((buf = malloc(len)) == NULL)
    712 		return;
    713 
    714 	(void) snprintf(buf, len, "<%s %s>", str, attr);
    715 	buf_add_str(b, buf);
    716 	free(buf);
    717 }
    718 
    719 /*
    720  * []----
    721  * | Utility functions
    722  * []----
    723  */
    724 static tgt_node_t *
    725 node_alloc()
    726 {
    727 	tgt_node_t	*x = (tgt_node_t *)calloc(sizeof (tgt_node_t), 1);
    728 
    729 	if (x == NULL)
    730 		return (NULL);
    731 
    732 	x->x_state = NodeAlloc;
    733 	return (x);
    734 }
    735 
    736 static void
    737 node_free(tgt_node_t *x)
    738 {
    739 	x->x_state = NodeFree;
    740 	if (x->x_name)
    741 		free(x->x_name);
    742 	if (x->x_value)
    743 		free(x->x_value);
    744 	free(x);
    745 }
    746 
    747 static Boolean_t
    748 node_name(tgt_node_t *x, const xmlChar *n)
    749 {
    750 	assert(x->x_state == NodeAlloc);
    751 	if ((n == NULL) || (strlen((char *)n) == 0))
    752 		return (False);
    753 
    754 	x->x_state = NodeName;
    755 	x->x_name = strip_space((char *)n);
    756 	return (True);
    757 }
    758 
    759 static Boolean_t
    760 node_value(tgt_node_t *x, const xmlChar *n, Boolean_t do_strip)
    761 {
    762 	assert(x->x_state == NodeName);
    763 	if ((n == NULL) || (strlen((char *)n) == NULL))
    764 		return (False);
    765 
    766 	x->x_state = NodeValue;
    767 	x->x_value = (do_strip == True) ?
    768 	    strip_space((char *)n) : strdup((char *)n);
    769 	return (True);
    770 }
    771 
    772 static tgt_node_t *
    773 node_parent(tgt_node_t *x)
    774 {
    775 	return (x->x_parent);
    776 }
    777 
    778 static tgt_node_t *
    779 node_child(tgt_node_t *x)
    780 {
    781 	tgt_node_t	*n;
    782 
    783 	if ((n = node_alloc()) == NULL)
    784 		return (NULL);
    785 
    786 	if (x->x_child == NULL) {
    787 		x->x_child = n;
    788 	} else {
    789 		n->x_sibling = x->x_child;
    790 		x->x_child = n;
    791 	}
    792 	n->x_parent = x;
    793 	return (n);
    794 }
    795 
    796 static tgt_node_t *
    797 node_alloc_attr(tgt_node_t *x)
    798 {
    799 	tgt_node_t	*n;
    800 	tgt_node_t	*next;
    801 
    802 	n = node_alloc();
    803 	if (x->x_attr == NULL) {
    804 		x->x_attr = n;
    805 	} else {
    806 		for (next = x->x_attr; next->x_sibling; next = next->x_sibling)
    807 			;
    808 		next->x_sibling = n;
    809 	}
    810 	if (n != NULL)
    811 		n->x_parent = x;
    812 	return (n);
    813 }
    814 
    815 static void
    816 buf_add_str(char **b, char *str)
    817 {
    818 	int	len;
    819 	int	olen	= 0;
    820 	char	*p = *b;
    821 
    822 	/*
    823 	 * Make sure we have enough room for the string and tag characters
    824 	 * plus a NULL byte.
    825 	 */
    826 	if (str == NULL)
    827 		return;
    828 
    829 	len = strlen(str) + 1;
    830 	if (p == NULL) {
    831 		if ((p = malloc(len)) == NULL)
    832 			return;
    833 	} else {
    834 		olen = strlen(p);
    835 		p = realloc(p, olen + len);
    836 	}
    837 	(void) strncpy(p + olen, str, len);
    838 	*b = p;
    839 }
    840 
    841 static void
    842 buf_add_node_attr(char **b, tgt_node_t *x)
    843 {
    844 	char		*buf;
    845 	tgt_node_t	*n;
    846 	int		len;
    847 
    848 	/* ---- null byte and starting '<' character ---- */
    849 	len = strlen(x->x_name) + 2;
    850 	if ((buf = malloc(len)) == NULL)
    851 		return;
    852 	(void) snprintf(buf, len, "<%s", x->x_name);
    853 	buf_add_str(b, buf);
    854 	free(buf);
    855 
    856 	for (n = x->x_attr; n; n = n->x_sibling) {
    857 		len = strlen(n->x_name) + strlen(n->x_value) + 5;
    858 		if ((buf = malloc(len)) == NULL)
    859 			return;
    860 		(void) snprintf(buf, len, " %s='%s'", n->x_name, n->x_value);
    861 		buf_add_str(b, buf);
    862 		free(buf);
    863 	}
    864 	buf_add_str(b, ">");
    865 }
    866 
    867 static void
    868 buf_add_comment(char **b, char *comment)
    869 {
    870 	char	*p	= *b;
    871 	int	len;
    872 	int	olen;
    873 
    874 	if (comment == NULL)
    875 		return;
    876 
    877 	/*
    878 	 * Room for the strings, plus the brackets and NULL byte
    879 	 */
    880 	len = strlen(comment) + strlen(XML_COMMENT_STR) +
    881 	    strlen(XML_COMMENT_END) + 3;
    882 
    883 	if (p == NULL)
    884 		p = malloc(len);
    885 	else {
    886 		olen = strlen(p);
    887 		p = realloc(p, olen + len);
    888 	}
    889 	(void) snprintf(p + olen, len, "<%s%s%s>", XML_COMMENT_STR, comment,
    890 	    XML_COMMENT_END);
    891 	*b = p;
    892 }
    893 
    894 static char *
    895 strip_space(char *value)
    896 {
    897 	char	*p;
    898 	char	*n;
    899 
    900 	for (p = value; p && *p; p++)
    901 		if (!isspace(*p))
    902 			break;
    903 	if ((p == NULL) || (*p == '\0'))
    904 		return (NULL);
    905 
    906 	p = strdup(p);
    907 	for (n = (p + strlen(p) - 1); n >= p; n--)
    908 		if (!isspace(*n)) {
    909 			n++;
    910 			break;
    911 		}
    912 	*n = '\0';
    913 	return (p);
    914 }
    915