7712 mandoc -Tlint does always exit with error code 0
[unleashed.git] / usr / src / cmd / lvm / metassist / xml / xml_convert.c
blobfb2ef57e60ebde1e1f642eb7283fafbfdd110252
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
20 * CDDL HEADER END
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
29 #include "xml_convert.h"
31 #include <errno.h>
32 #include <string.h>
33 #include <libintl.h>
34 #include <libxslt/xslt.h>
35 #include <libxslt/xsltInternals.h>
36 #include <libxslt/transform.h>
37 #include <libxslt/xsltutils.h>
38 #include <locale.h>
39 #include <unistd.h>
40 #include "volume_error.h"
41 #include "volume_output.h"
42 #include "volume_string.h"
45 * IDs for localized messages in the generated command script
48 #define CMD_MSG_ENVIRONMENT "Environment"
49 #define CMD_MSG_AMEND_PATH "Amend PATH"
50 #define CMD_MSG_DISK_SET_NAME "Disk set name"
51 #define CMD_MSG_FUNCTIONS "Functions"
52 /* CSTYLED */
53 #define CMD_MSG_ECHO_AND_EXEC "Echo (verbose) and exec given command, exit on error"
54 #define CMD_MSG_GET_FULL_PATH "Get full /dev/rdsk path of given slice"
55 /* CSTYLED */
56 #define CMD_MSG_FMTHARD_SPECIAL "Run fmthard, ignore partboot error, error if output"
57 #define CMD_MSG_MAIN "Main"
58 #define CMD_MSG_VERIFY_ROOT "Verify root"
59 #define CMD_MSG_RUN_AS_ROOT "This script must be run as root."
60 #define CMD_MSG_CHECK_FOR_VERBOSE "Check for verbose option"
61 #define CMD_MSG_DOES_DISK_SET_EXIST "Does the disk set exist?"
62 #define CMD_MSG_TAKE_DISK_SET "Take control of disk set"
63 #define CMD_MSG_CREATE_THE_DISK_SET "Create the disk set"
64 #define CMD_MSG_ADD_DISKS_TO_SET "Add disks to set"
65 #define CMD_MSG_FORMAT_SLICES "Format slices"
66 #define CMD_MSG_CREATE "Create {1} {2}"
67 #define CMD_MSG_DOES_EXIST "Does {1} exist?"
68 #define CMD_MSG_ADD_SLICES_TO "Add slices to {1}"
69 /* CSTYLED */
70 #define CMD_MSG_ASSOCIATE_WITH_HSP "Associate {1} {2} with hot spare pool {3}"
73 * ******************************************************************
75 * Data types
77 * ******************************************************************
81 * Encapsulates the parsing of an XML attribute
83 typedef struct {
85 /* The name of the attribute */
86 char *name;
89 * A function to validate and set the XML attribute value in
90 * the given devconfig_t structure.
92 * @param name
93 * the name of the XML attribute
95 * @param value
96 * the value of the XML attribute
98 * @return 0 if the given value was valid and set
99 * successfully, non-zero otherwise.
101 int (*validate_set)(devconfig_t *device, char *name, char *value);
104 * A function to get the XML attribute value in the given
105 * devconfig_t structure.
107 * @param name
108 * the name of the XML attribute
110 * @param value
111 * the value of the XML attribute
113 * @return 0 if the given value was retrieved
114 * successfully, non-zero otherwise.
116 int (*get_as_string)(devconfig_t *device, char *name, char **value);
117 } attr_t;
120 * Encapsulates the parsing of an XML element
122 typedef struct {
123 /* The name of the element */
124 char *name;
126 /* The type of element to set in the devconfig_t */
127 component_type_t type;
130 * When converting from XML to a devconfig_t hierarchy,
131 * indicates whether to create a new devconfig_t structure in
132 * the hierarchy when this XML element is encountered.
134 boolean_t is_hierarchical;
137 * If is_hierarchical is B_TRUE, whether to use an existing
138 * devconfig_t structure of this type when this element is
139 * encountered
141 boolean_t singleton;
143 /* The valid XML attributes for this element */
144 attr_t *attributes;
145 } element_t;
147 typedef struct {
148 char *msgid;
149 char *message;
150 } l10nmessage_t;
153 * ******************************************************************
155 * Function prototypes
157 * ******************************************************************
160 static int validate_doc(xmlDocPtr doc, const char *name, const char *systemID);
161 static int devconfig_to_xml(
162 xmlNodePtr parent, element_t elements[], devconfig_t *device);
163 static int xml_to_devconfig(
164 xmlNodePtr cur, element_t elements[], devconfig_t *device);
165 static int compare_is_a_diskset(void *obj1, void *obj2);
166 static xmlNodePtr xml_find_node(
167 xmlNodePtr node, xmlChar *element, xmlChar *name);
168 static xmlDocPtr create_localized_message_doc();
169 static int create_localized_message_file(char **tmpfile);
170 static int strtobool(char *str, boolean_t *value);
171 static int ofprintf_terse(void *unused, char *fmt, ...);
172 static int ofprintf_verbose(void *unused, char *fmt, ...);
174 static int validate_set_size(
175 devconfig_t *volume, char *attr, char *value);
176 static int validate_set_size_in_blocks(
177 devconfig_t *slice, char *attr, char *value);
178 static int validate_set_diskset_name(
179 devconfig_t *diskset, char *attr, char *name);
180 static int validate_add_available_name(
181 devconfig_t *device, char *attr, char *name);
182 static int validate_add_unavailable_name(
183 devconfig_t *device, char *attr, char *name);
184 static int validate_set_hsp_name(
185 devconfig_t *hsp, char *attr, char *name);
186 static int validate_set_disk_name(
187 devconfig_t *disk, char *attr, char *name);
188 static int validate_set_slice_name(
189 devconfig_t *slice, char *attr, char *name);
190 static int validate_set_slice_start_block(
191 devconfig_t *slice, char *attr, char *value);
192 static int validate_set_volume_name(
193 devconfig_t *volume, char *attr, char *name);
194 static int validate_set_stripe_interlace(
195 devconfig_t *stripe, char *attr, char *value);
196 static int validate_set_stripe_mincomp(
197 devconfig_t *stripe, char *attr, char *value);
198 static int validate_set_stripe_maxcomp(
199 devconfig_t *stripe, char *attr, char *value);
200 static int validate_set_volume_usehsp(
201 devconfig_t *volume, char *attr, char *value);
202 static int validate_set_mirror_nsubmirrors(
203 devconfig_t *mirror, char *attr, char *value);
204 static int validate_set_mirror_read(
205 devconfig_t *mirror, char *attr, char *value);
206 static int validate_set_mirror_write(
207 devconfig_t *mirror, char *attr, char *value);
208 static int validate_set_mirror_passnum(
209 devconfig_t *mirror, char *attr, char *value);
210 static int validate_set_volume_redundancy(
211 devconfig_t *volume, char *attr, char *value);
212 static int validate_set_volume_datapaths(
213 devconfig_t *volume, char *attr, char *value);
215 static int get_as_string_name(
216 devconfig_t *device, char *attr, char **value);
217 static int get_as_string_mirror_passnum(
218 devconfig_t *mirror, char *attr, char **value);
219 static int get_as_string_mirror_read(
220 devconfig_t *mirror, char *attr, char **value);
221 static int get_as_string_mirror_write(
222 devconfig_t *mirror, char *attr, char **value);
223 static int get_as_string_size_in_blocks(
224 devconfig_t *device, char *attr, char **value);
225 static int get_as_string_slice_start_block(
226 devconfig_t *slice, char *attr, char **value);
227 static int get_as_string_stripe_interlace(
228 devconfig_t *stripe, char *attr, char **value);
231 * ******************************************************************
233 * Data
235 * ******************************************************************
238 /* Valid units for the size attribute */
239 units_t size_units[] = {
240 {UNIT_KILOBYTES, BYTES_PER_KILOBYTE},
241 {UNIT_MEGABYTES, BYTES_PER_MEGABYTE},
242 {UNIT_GIGABYTES, BYTES_PER_GIGABYTE},
243 {UNIT_TERABYTES, BYTES_PER_TERABYTE},
244 {NULL, 0}
247 /* Valid units for the interlace attribute */
248 units_t interlace_units[] = {
249 {UNIT_BLOCKS, BYTES_PER_BLOCK},
250 {UNIT_KILOBYTES, BYTES_PER_KILOBYTE},
251 {UNIT_MEGABYTES, BYTES_PER_MEGABYTE},
252 {NULL, 0}
255 /* <diskset> attributes */
256 static attr_t diskset_attrs[] = {
257 { ATTR_NAME, validate_set_diskset_name, get_as_string_name },
258 { NULL, NULL, NULL }
261 /* <available> attributes */
262 static attr_t available_attrs[] = {
263 { ATTR_NAME, validate_add_available_name, NULL },
264 { NULL, NULL, NULL }
267 /* <unavailable> attributes */
268 static attr_t unavailable_attrs[] = {
269 { ATTR_NAME, validate_add_unavailable_name, NULL },
270 { NULL, NULL, NULL }
273 /* <hsp> attributes */
274 static attr_t hsp_attrs[] = {
275 { ATTR_NAME, validate_set_hsp_name, get_as_string_name },
276 { NULL, NULL, NULL }
279 /* <disk> attributes */
280 static attr_t disk_attrs[] = {
281 { ATTR_NAME, validate_set_disk_name, get_as_string_name },
282 { NULL, NULL, NULL }
285 /* <slice> attributes */
286 static attr_t slice_attrs[] = {
287 { ATTR_NAME, validate_set_slice_name, get_as_string_name },
288 { ATTR_SIZEINBLOCKS, validate_set_size_in_blocks,
289 get_as_string_size_in_blocks },
290 { ATTR_SLICE_STARTSECTOR, validate_set_slice_start_block,
291 get_as_string_slice_start_block },
292 { NULL, NULL, NULL }
295 /* <stripe> attributes */
296 static attr_t stripe_attrs[] = {
297 { ATTR_NAME, validate_set_volume_name, get_as_string_name },
298 { ATTR_SIZEINBYTES, validate_set_size, NULL },
299 { ATTR_STRIPE_MINCOMP, validate_set_stripe_mincomp, NULL },
300 { ATTR_STRIPE_MAXCOMP, validate_set_stripe_maxcomp, NULL },
301 { ATTR_STRIPE_INTERLACE, validate_set_stripe_interlace,
302 get_as_string_stripe_interlace },
303 { ATTR_VOLUME_USEHSP, validate_set_volume_usehsp, NULL },
304 { NULL, NULL, NULL }
307 /* <concat> attributes */
308 static attr_t concat_attrs[] = {
309 { ATTR_NAME, validate_set_volume_name, get_as_string_name },
310 { ATTR_SIZEINBYTES, validate_set_size, NULL },
311 { ATTR_VOLUME_USEHSP, validate_set_volume_usehsp, NULL },
312 { NULL, NULL, NULL }
315 /* <mirror> attributes */
316 static attr_t mirror_attrs[] = {
317 { ATTR_NAME, validate_set_volume_name, get_as_string_name },
318 { ATTR_MIRROR_NSUBMIRRORS, validate_set_mirror_nsubmirrors, NULL },
319 { ATTR_SIZEINBYTES, validate_set_size, NULL },
320 { ATTR_MIRROR_READ, validate_set_mirror_read,
321 get_as_string_mirror_read },
322 { ATTR_MIRROR_WRITE, validate_set_mirror_write,
323 get_as_string_mirror_write },
324 { ATTR_MIRROR_PASSNUM, validate_set_mirror_passnum,
325 get_as_string_mirror_passnum },
326 { ATTR_VOLUME_USEHSP, validate_set_volume_usehsp, NULL },
327 { NULL, NULL, NULL }
330 /* <volume> attributes */
331 static attr_t volume_attrs[] = {
332 { ATTR_NAME, validate_set_volume_name, get_as_string_name },
333 { ATTR_SIZEINBYTES, validate_set_size, NULL },
334 { ATTR_VOLUME_REDUNDANCY, validate_set_volume_redundancy, NULL },
335 { ATTR_VOLUME_FAULTRECOVERY, validate_set_volume_usehsp, NULL },
336 { ATTR_VOLUME_DATAPATHS, validate_set_volume_datapaths, NULL },
337 { NULL, NULL, NULL }
340 /* volume-request elements */
341 static element_t request_elements[] = {
342 { ELEMENT_DISKSET, TYPE_DISKSET, B_FALSE, B_FALSE, diskset_attrs },
343 { ELEMENT_AVAILABLE, TYPE_UNKNOWN, B_FALSE, B_FALSE, available_attrs },
344 { ELEMENT_UNAVAILABLE, TYPE_UNKNOWN, B_FALSE, B_FALSE,
345 unavailable_attrs },
346 { ELEMENT_HSP, TYPE_HSP, B_TRUE, B_FALSE, hsp_attrs },
347 { ELEMENT_SLICE, TYPE_SLICE, B_TRUE, B_FALSE, slice_attrs },
348 { ELEMENT_STRIPE, TYPE_STRIPE, B_TRUE, B_FALSE, stripe_attrs },
349 { ELEMENT_CONCAT, TYPE_CONCAT, B_TRUE, B_FALSE, concat_attrs },
350 { ELEMENT_MIRROR, TYPE_MIRROR, B_TRUE, B_FALSE, mirror_attrs },
351 { ELEMENT_VOLUME, TYPE_VOLUME, B_TRUE, B_FALSE, volume_attrs },
352 { NULL, NULL, B_FALSE, B_FALSE, NULL }
355 /* volume-defaults elements */
356 static element_t default_elements[] = {
357 { ELEMENT_DISKSET, TYPE_DISKSET, B_TRUE, B_FALSE, diskset_attrs },
358 { ELEMENT_AVAILABLE, TYPE_UNKNOWN, B_FALSE, B_TRUE, available_attrs },
359 { ELEMENT_UNAVAILABLE, TYPE_UNKNOWN, B_FALSE, B_TRUE,
360 unavailable_attrs },
361 { ELEMENT_HSP, TYPE_HSP, B_TRUE, B_TRUE, hsp_attrs },
362 { ELEMENT_SLICE, TYPE_SLICE, B_TRUE, B_TRUE, slice_attrs },
363 { ELEMENT_STRIPE, TYPE_STRIPE, B_TRUE, B_TRUE, stripe_attrs },
364 { ELEMENT_CONCAT, TYPE_CONCAT, B_TRUE, B_TRUE, concat_attrs },
365 { ELEMENT_MIRROR, TYPE_MIRROR, B_TRUE, B_TRUE, mirror_attrs },
366 { ELEMENT_VOLUME, TYPE_VOLUME, B_TRUE, B_TRUE, volume_attrs },
367 { NULL, NULL, B_FALSE, B_FALSE, NULL }
370 /* volume-config elements */
371 static element_t config_elements[] = {
372 { ELEMENT_DISKSET, TYPE_DISKSET, B_FALSE, B_FALSE, diskset_attrs },
373 { ELEMENT_DISK, TYPE_DRIVE, B_TRUE, B_FALSE, disk_attrs },
374 { ELEMENT_SLICE, TYPE_SLICE, B_TRUE, B_FALSE, slice_attrs },
375 { ELEMENT_HSP, TYPE_HSP, B_TRUE, B_FALSE, hsp_attrs },
376 { ELEMENT_STRIPE, TYPE_STRIPE, B_TRUE, B_FALSE, stripe_attrs },
377 { ELEMENT_CONCAT, TYPE_CONCAT, B_TRUE, B_FALSE, concat_attrs },
378 { ELEMENT_MIRROR, TYPE_MIRROR, B_TRUE, B_FALSE, mirror_attrs },
379 { NULL, NULL, B_FALSE, B_FALSE, NULL }
383 * ******************************************************************
385 * External functions
387 * ******************************************************************
391 * Initialize the XML parser, setting defaults across all XML
392 * routines.
394 void
395 init_xml()
397 /* COMPAT: Do not generate nodes for formatting spaces */
398 LIBXML_TEST_VERSION
399 xmlKeepBlanksDefault(0);
401 /* Turn on line numbers for debugging */
402 xmlLineNumbersDefault(1);
404 /* Substitute entities as files are parsed */
405 xmlSubstituteEntitiesDefault(1);
407 /* Don't load external entity subsets */
408 xmlLoadExtDtdDefaultValue = 0;
410 /* Don't validate against DTD by default */
411 xmlDoValidityCheckingDefaultValue = 0;
413 /* Set up output handlers for XML parsing */
414 xmlDefaultSAXHandler.warning = (warningSAXFunc)ofprintf_verbose;
415 xmlDefaultSAXHandler.error = (errorSAXFunc)ofprintf_terse;
416 xmlDefaultSAXHandler.fatalError = (fatalErrorSAXFunc)ofprintf_terse;
420 * Clean up any remaining structures before exiting.
422 void
423 cleanup_xml()
425 xsltCleanupGlobals();
426 xmlCleanupParser();
430 * Converts a volume-request XML document into a request_t.
432 * @param doc
433 * an existing volume-request XML document
435 * @param request
436 * RETURN: a new request_t which must be freed via
437 * free_request
439 * @return 0 on success, non-zero otherwise.
442 xml_to_request(
443 xmlDocPtr doc,
444 request_t **request)
446 int error = 0;
448 *request = NULL;
450 /* Validate doc against known DTD */
451 if ((error = validate_doc(
452 doc, ELEMENT_VOLUMEREQUEST, VOLUME_REQUEST_DTD_LOC)) == 0) {
454 /* Create a request */
455 if ((error = new_request(request)) == 0) {
457 /* Convert the XML doc into a request_t */
458 error = xml_to_devconfig(xmlDocGetRootElement(doc),
459 request_elements, request_get_diskset_req(*request));
463 return (error);
467 * Converts a volume-defaults XML document into a defaults_t.
469 * @param doc
470 * an existing volume-defaults XML document
472 * @param defaults
473 * RETURN: a new defaults_t which must be freed via
474 * free_defaults
476 * @return 0 on success, non-zero otherwise.
479 xml_to_defaults(
480 xmlDocPtr doc,
481 defaults_t **defaults)
483 int error = 0;
485 *defaults = NULL;
487 /* Validate doc against known DTD */
488 if ((error = validate_doc(doc, ELEMENT_VOLUMEDEFAULTS,
489 VOLUME_DEFAULTS_DTD_LOC)) == 0) {
491 /* Create request defaults */
492 if ((error = new_defaults(defaults)) == 0) {
494 devconfig_t *global;
496 /* Get defaults for all disk sets */
497 if ((error = defaults_get_diskset_by_name(
498 *defaults, NULL, &global)) == 0) {
500 /* Populate the global devconfig_t from the XML doc */
501 if ((error = xml_to_devconfig(xmlDocGetRootElement(doc),
502 default_elements, global)) == 0) {
504 /* Get the components of the global devconfig_t */
505 dlist_t *list = devconfig_get_components(global);
508 * Move all named disk set settings out from
509 * under global settings
511 /* CONSTANTCONDITION */
512 while (1) {
513 dlist_t *removed = NULL;
514 devconfig_t *component;
516 /* Remove named disk set from under global */
517 list = dlist_remove_equivalent_item(
518 list, NULL, compare_is_a_diskset, &removed);
520 if (removed == NULL) {
521 /* No named disk set found */
522 break;
525 component = removed->obj;
527 /* Append named disk set to disk set list */
528 defaults_set_disksets(*defaults,
529 dlist_append(dlist_new_item(component),
530 defaults_get_disksets(*defaults), AT_TAIL));
537 return (error);
541 * Converts a volume-config XML document into a devconfig_t.
543 * @param doc
544 * an existing volume-config XML document
546 * @param config
547 * RETURN: a new devconfig_t which must be freed via
548 * free_devconfig
550 * @return 0 on success, non-zero otherwise.
553 xml_to_config(
554 xmlDocPtr doc,
555 devconfig_t **config)
557 int error = 0;
559 *config = NULL;
561 /* Validate doc against known DTD */
562 if ((error = validate_doc(
563 doc, ELEMENT_VOLUMECONFIG, VOLUME_CONFIG_DTD_LOC)) == 0) {
565 /* Create a devconfig_t */
566 if ((error = new_devconfig(config, TYPE_DISKSET)) == 0) {
568 /* Populate the devconfig_t from the XML doc */
569 error = xml_to_devconfig(
570 xmlDocGetRootElement(doc), config_elements, *config);
574 return (error);
578 * Converts a devconfig_t into a volume-config XML document.
580 * @param config
581 * an existing devconfig_t representing a volume
582 * configuration.
584 * @param doc
585 * RETURN: a new volume-config XML document which must be
586 * freed via xmlFreeDoc
588 * @return 0 on success, non-zero otherwise.
591 config_to_xml(
592 devconfig_t *config,
593 xmlDocPtr *doc)
595 xmlNodePtr root;
596 int error = 0;
598 /* Create the XML document */
599 *doc = xmlNewDoc((xmlChar *)"1.0");
601 /* Create the root node */
602 root = xmlNewDocNode(
603 *doc, NULL, (xmlChar *)ELEMENT_VOLUMECONFIG, NULL);
604 xmlAddChild((xmlNodePtr)*doc, (xmlNodePtr)root);
606 /* Create sub-nodes from the config devconfig_t */
607 if ((error = devconfig_to_xml(root, config_elements, config)) == 0) {
609 /* Add DTD node and validate */
610 error = validate_doc(
611 *doc, ELEMENT_VOLUMECONFIG, VOLUME_CONFIG_DTD_LOC);
614 if (error) {
615 xmlFreeDoc(*doc);
618 return (error);
622 * Converts a volume-config XML document into a Bourne shell script.
624 * @param doc
625 * an existing volume-config XML document
627 * @param commands
628 * RETURN: a new char* which must be freed
630 * @return 0 on success, non-zero otherwise.
633 xml_to_commands(
634 xmlDocPtr doc,
635 char **commands)
637 char *tmpfile = NULL;
638 int error = 0;
639 xsltStylesheetPtr style = NULL;
641 /* Read in XSL stylesheet as a normal XML document */
642 xmlDocPtr xsl_doc = xmlSAXParseFile((xmlSAXHandlerPtr)
643 &xmlDefaultSAXHandler, VOLUME_COMMAND_XSL_LOC, 0);
645 if (xsl_doc != NULL && xsl_doc->xmlChildrenNode != NULL) {
648 * Find the "msgfile" variable node. This is where
649 * we'll set the location of the file we'll create
650 * containing the localized messages.
652 xmlNodePtr msgfile_node = xml_find_node(
653 xmlDocGetRootElement(xsl_doc), (xmlChar *)ELEMENT_VARIABLE,
654 (xmlChar *)NAME_L10N_MESSAGE_FILE);
657 * Find the "lang" node. This is where we'll set the
658 * current locale.
660 xmlNodePtr lang_node = xml_find_node(xmlDocGetRootElement(xsl_doc),
661 (xmlChar *)ELEMENT_PARAM, (xmlChar *)NAME_LANG);
664 * Ignore if the nodes are not found -- the script
665 * will default to the C locale.
667 if (msgfile_node != NULL && lang_node != NULL) {
668 /* Get/set current locale in the "lang" node */
669 char *locale = setlocale(LC_MESSAGES, NULL);
670 xmlNodeSetContent(lang_node, (xmlChar *)locale);
672 /* Write localized messages to a temporary file */
673 if ((error = create_localized_message_file(&tmpfile)) == 0) {
675 char *newsel;
677 /* Clear current value of select attribute, if any */
678 xmlChar *cursel = xmlGetProp(
679 msgfile_node, (xmlChar *)ATTR_SELECT);
680 if (cursel != NULL) {
681 xmlFree(cursel);
685 * The select attribute calls the XSLT function
686 * document() to load an external XML file
688 newsel = stralloccat(3, "document('", tmpfile, "')");
690 if (newsel == NULL) {
691 volume_set_error(gettext("out of memory"));
692 error = -1;
693 } else {
695 /* Set the new value of the select attribute */
696 xmlSetProp(msgfile_node,
697 (xmlChar *)ATTR_SELECT, (xmlChar *)newsel);
699 free(newsel);
704 if (error == 0) {
705 style = xsltParseStylesheetDoc(xsl_doc);
709 if (style == NULL) {
710 volume_set_error(
711 gettext("could not load stylesheet from %s"),
712 VOLUME_COMMAND_XSL_LOC);
713 error = -1;
714 } else {
716 xmlDocPtr result = xsltApplyStylesheet(style, doc, NULL);
718 if (result == NULL) {
719 volume_set_error(
720 gettext("could not apply stylesheet to volume-config"));
721 error = -1;
722 } else {
723 int length;
725 if (xsltSaveResultToString((xmlChar **)commands,
726 &length, result, style) == -1) {
727 error = ENOMEM;
731 xsltFreeStylesheet(style);
734 if (tmpfile != NULL) {
735 /* Ignore failure */
736 unlink(tmpfile);
738 free(tmpfile);
741 return (error);
745 * ******************************************************************
747 * Static functions
749 * ******************************************************************
753 * Sets the external DTD node in the given XML document and then
754 * validates it.
756 * @param doc
757 * an existing XML document
759 * @param name
760 * the expected root element name of the XML document
762 * @param systemID
763 * the location of the DTD
765 * @return 0 on success, non-zero otherwise.
767 static int
768 validate_doc(
769 xmlDocPtr doc,
770 const char *name,
771 const char *systemID)
773 xmlValidCtxt context;
774 xmlDtdPtr dtd;
776 if (doc == NULL) {
777 volume_set_error(gettext("NULL %s document"), name);
778 return (-1);
782 * Assume that we can't trust any DTD but our own.
785 /* Was a DTD (external or internal) included in the document? */
786 if ((dtd = xmlGetIntSubset(doc)) != NULL) {
787 /* Remove the DTD node */
788 oprintf(OUTPUT_DEBUG, gettext("Removing DTD from %s\n"), name);
789 xmlUnlinkNode((xmlNodePtr)dtd);
790 xmlFreeDtd(dtd);
793 /* Create the (external) DTD node */
794 oprintf(OUTPUT_DEBUG,
795 gettext("Creating new external DTD for %s\n"), name);
796 dtd = xmlCreateIntSubset(
797 doc, (xmlChar *)name, NULL, (xmlChar *)systemID);
798 if (dtd == NULL) {
799 volume_set_error(
800 gettext("could not create DTD node from %s"), systemID);
801 return (-1);
804 /* Validate against DTD */
805 oprintf(OUTPUT_DEBUG, gettext("Validating %s against DTD\n"), name);
806 context.userData = NULL;
807 context.error = (xmlValidityErrorFunc)ofprintf_terse;
808 context.warning = (xmlValidityWarningFunc)ofprintf_terse;
809 if (!xmlValidateDocument(&context, doc)) {
810 volume_set_error(gettext("invalid %s"), name);
811 return (-1);
814 return (0);
818 * Converts a devconfig_t into an XML node subject to the rules in
819 * the given element_t array.
821 * @param parent
822 * the XML node to which to add new XML nodes resulting
823 * from conversion of the given devconfig_t
825 * @param elements
826 * the element_ts that describe the structure of the XML
827 * document and govern the conversion of the given
828 * devconfig_t
830 * @param device
831 * the devconfig_t to convert
833 * @return 0 on success, non-zero otherwise.
835 static int
836 devconfig_to_xml(
837 xmlNodePtr parent,
838 element_t elements[],
839 devconfig_t *device)
841 int i;
842 int error = 0;
843 xmlNodePtr node = NULL;
845 /* Get device type */
846 component_type_t type;
847 if ((error = devconfig_get_type(device, &type)) != 0) {
848 return (error);
851 /* Search for this element definition */
852 for (i = 0; elements[i].name != NULL; i++) {
853 element_t *element = &(elements[i]);
855 if (element->type == type) {
856 int j;
857 char **array;
858 dlist_t *components;
860 oprintf(OUTPUT_DEBUG, gettext("Element: %s\n"),
861 devconfig_type_to_str(type));
863 /* Create the XML node */
864 node = xmlNewChild(
865 parent, NULL, (xmlChar *)element->name, NULL);
867 /* For each attribute defined for this element... */
868 for (j = 0; element->attributes[j].name != NULL; j++) {
869 attr_t *attribute = &(element->attributes[j]);
870 char *value;
872 /* Is there a valid accessor for this attribute? */
873 if (attribute->get_as_string != NULL) {
875 /* Get the attribute value from the device */
876 switch (error = attribute->get_as_string(
877 device, attribute->name, &value)) {
879 /* Attribute is set in this device */
880 case 0:
881 oprintf(OUTPUT_DEBUG, " %s: %s\n",
882 attribute->name, value);
884 /* Set the value in the XML node */
885 xmlSetProp(node, (uchar_t *)attribute->name,
886 (uchar_t *)value);
887 free(value);
889 /* FALLTHROUGH */
891 /* Attribute is not set in this device */
892 case ERR_ATTR_UNSET:
894 error = 0;
895 break;
897 /* Error */
898 default:
899 return (error);
904 /* Is this node hierarchical? */
905 if (element->is_hierarchical == B_FALSE) {
906 node = parent;
909 /* Create <available> nodes */
910 array = devconfig_get_available(device);
911 if (array != NULL) {
912 for (j = 0; array[j] != NULL; j++) {
913 xmlNodePtr child = xmlNewChild(
914 node, NULL, (xmlChar *)ELEMENT_AVAILABLE, NULL);
915 xmlSetProp(child,
916 (xmlChar *)ATTR_NAME, (xmlChar *)array[j]);
920 /* Create <unavailable> nodes */
921 array = devconfig_get_unavailable(device);
922 if (array != NULL) {
923 for (j = 0; array[j] != NULL; j++) {
924 xmlNodePtr child = xmlNewChild(
925 node, NULL, (xmlChar *)ELEMENT_UNAVAILABLE, NULL);
926 xmlSetProp(child,
927 (xmlChar *)ATTR_NAME, (xmlChar *)array[j]);
932 * Recursively convert subcomponents of this device to
933 * XML, taking care to encode them in the order
934 * specified in the element_t list (which should
935 * mirror what's expected by the DTD).
938 /* For each element type... */
939 for (j = 0; elements[j].name != NULL; j++) {
941 /* For each component of this device... */
942 for (components = devconfig_get_components(device);
943 components != NULL && error == 0;
944 components = components->next) {
946 devconfig_t *component = (devconfig_t *)components->obj;
947 component_type_t t;
949 /* Are the types the same? */
950 if ((error = devconfig_get_type(component, &t)) != 0) {
951 return (error);
952 } else {
953 if (elements[j].type == t) {
954 /* Encode child */
955 error = devconfig_to_xml(
956 node, elements, component);
962 /* Element found */
963 break;
967 /* Was this device successfully converted? */
968 if (node == NULL) {
969 volume_set_error(
970 gettext("can't convert device of type \"%s\" to XML element"),
971 devconfig_type_to_str(type));
972 error = -1;
975 return (error);
979 * Converts an XML node into a devconfig_t subject to the rules in
980 * the given element_t array.
982 * @param cure
983 * the existing XML node to convert
985 * @param elements
986 * the element_ts that describe the structure of the XML
987 * document and govern the conversion of the given XML
988 * node
990 * @param device
991 * the devconfig_t node to which to add new devconfig_ts
992 * resulting from conversion of the given XML node
994 * @return 0 on success, non-zero otherwise.
996 static int
997 xml_to_devconfig(
998 xmlNodePtr cur,
999 element_t elements[],
1000 devconfig_t *device)
1002 int error = 0;
1004 /* For each child node... */
1005 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
1006 int i;
1007 boolean_t parsed_elem = B_FALSE;
1009 /* Search for this element definition */
1010 for (i = 0; elements[i].name != NULL; i++) {
1011 element_t *element = &(elements[i]);
1013 if (xmlStrcmp(cur->name, (xmlChar *)element->name) == 0) {
1014 int j;
1015 devconfig_t *component = NULL;
1017 /* Flag that this element has been parsed */
1018 parsed_elem = B_TRUE;
1020 oprintf(OUTPUT_DEBUG, gettext("line %d: Element <%s>\n"),
1021 XML_GET_LINE(cur), cur->name);
1023 /* Should a new device be created for this element? */
1024 if (element->is_hierarchical == B_TRUE) {
1026 /* Should we use an existing device of this type? */
1027 if (element->singleton) {
1028 devconfig_get_component(
1029 device, element->type, &component, B_FALSE);
1032 if (component == NULL) {
1033 oprintf(OUTPUT_DEBUG,
1034 gettext("Creating new device\n"));
1036 /* Create device of this type */
1037 if ((error = new_devconfig(
1038 &component, element->type)) != 0) {
1039 return (error);
1042 /* Add component to the toplevel device */
1043 devconfig_set_components(
1044 device, dlist_append(dlist_new_item(component),
1045 devconfig_get_components(device), AT_TAIL));
1047 } else {
1048 component = device;
1051 /* For each attribute defined for this element... */
1052 for (j = 0; element->attributes[j].name != NULL; j++) {
1053 attr_t *attribute = &(element->attributes[j]);
1055 /* Get the value of this attribute */
1056 char *value = (char *)
1057 xmlGetProp(cur, (xmlChar *)attribute->name);
1059 /* Was this attribute specified? */
1060 if (value != NULL) {
1061 oprintf(OUTPUT_DEBUG,
1062 gettext("line %d:\tAttribute %s=%s\n"),
1063 XML_GET_LINE(cur), attribute->name, value);
1065 /* Set this value in the device */
1066 if ((error = attribute->validate_set(
1067 component, attribute->name, value)) != 0) {
1068 return (error);
1073 /* Get recursive sub-elements */
1074 if ((error = xml_to_devconfig(
1075 cur, elements, component)) != 0) {
1076 return (error);
1079 /* Element found */
1080 break;
1085 /* Make sure all non-text/comment elements were parsed */
1086 if (parsed_elem == B_FALSE &&
1087 xmlStrcmp(cur->name, (xmlChar *)ELEMENT_TEXT) != 0 &&
1088 xmlStrcmp(cur->name, (xmlChar *)ELEMENT_COMMENT) != 0) {
1090 oprintf(OUTPUT_DEBUG, gettext("Element <%s> NOT PARSED!!!\n"),
1091 cur->name);
1095 return (0);
1099 * Returns 0 if obj2 (devconfig_t *) is a disk set, 1 otherwise.
1101 static int
1102 compare_is_a_diskset(
1103 void *obj1,
1104 void *obj2)
1106 return (devconfig_isA(
1107 (devconfig_t *)obj2, TYPE_DISKSET) == B_TRUE ? 0 : 1);
1111 * Recursively searches the given xmlNodePtr for an element of the
1112 * specified type and name.
1114 * @param node
1115 * the root node to search
1117 * @param element
1118 * the name of the element type
1120 * @param name
1121 * the value of the name attribute
1123 * @return a valid xmlNodePtr if an element of the specified
1124 * type and name was found, NULL otherwise.
1126 static xmlNodePtr
1127 xml_find_node(
1128 xmlNodePtr node,
1129 xmlChar *element,
1130 xmlChar *name)
1132 xmlNodePtr child;
1134 /* Is the element the right type? */
1135 if (xmlStrcmp(element, node->name) == 0 &&
1137 /* Does this element's name attribute match? */
1138 xmlStrcmp(name, xmlGetProp(node, (xmlChar *)ATTR_NAME)) == 0) {
1140 return (node);
1143 /* Check child nodes */
1144 for (child = node->xmlChildrenNode; child != NULL;
1145 child = child->next) {
1146 xmlNodePtr found = xml_find_node(child, element, name);
1148 if (found != NULL) {
1149 return (found);
1153 return (NULL);
1157 * Creates an XML document containing all of the localized message
1158 * strings for the generated command script.
1160 * @return a xmlDocPtr which must be freed via xmlFreeDoc
1162 static xmlDocPtr
1163 create_localized_message_doc()
1165 int i;
1166 char *locale;
1167 xmlDocPtr doc;
1168 xmlNodePtr root;
1169 l10nmessage_t _cmd_messages[21];
1171 /* Create the XML document */
1172 doc = xmlNewDoc((xmlChar *)"1.0");
1174 /* Create the root node */
1175 root = xmlNewDocNode(
1176 doc, NULL, (xmlChar *)ELEMENT_L10N, NULL);
1177 xmlAddChild((xmlNodePtr) doc, (xmlNodePtr)root);
1179 _cmd_messages[0].msgid = CMD_MSG_ENVIRONMENT;
1180 _cmd_messages[0].message = gettext(CMD_MSG_ENVIRONMENT);
1181 _cmd_messages[1].msgid = CMD_MSG_AMEND_PATH;
1182 _cmd_messages[1].message = gettext(CMD_MSG_AMEND_PATH);
1183 _cmd_messages[2].msgid = CMD_MSG_DISK_SET_NAME;
1184 _cmd_messages[2].message = gettext(CMD_MSG_DISK_SET_NAME);
1185 _cmd_messages[3].msgid = CMD_MSG_FUNCTIONS;
1186 _cmd_messages[3].message = gettext(CMD_MSG_FUNCTIONS);
1187 _cmd_messages[4].msgid = CMD_MSG_ECHO_AND_EXEC;
1188 _cmd_messages[4].message = gettext(CMD_MSG_ECHO_AND_EXEC);
1189 _cmd_messages[5].msgid = CMD_MSG_FMTHARD_SPECIAL;
1190 _cmd_messages[5].message = gettext(CMD_MSG_FMTHARD_SPECIAL);
1191 _cmd_messages[6].msgid = CMD_MSG_GET_FULL_PATH;
1192 _cmd_messages[6].message = gettext(CMD_MSG_GET_FULL_PATH);
1193 _cmd_messages[7].msgid = CMD_MSG_MAIN;
1194 _cmd_messages[7].message = gettext(CMD_MSG_MAIN);
1195 _cmd_messages[8].msgid = CMD_MSG_VERIFY_ROOT;
1196 _cmd_messages[8].message = gettext(CMD_MSG_VERIFY_ROOT);
1197 _cmd_messages[9].msgid = CMD_MSG_RUN_AS_ROOT;
1198 _cmd_messages[9].message = gettext(CMD_MSG_RUN_AS_ROOT);
1199 _cmd_messages[10].msgid = CMD_MSG_CHECK_FOR_VERBOSE;
1200 _cmd_messages[10].message = gettext(CMD_MSG_CHECK_FOR_VERBOSE);
1201 _cmd_messages[11].msgid = (CMD_MSG_DOES_DISK_SET_EXIST);
1202 _cmd_messages[11].message = gettext(CMD_MSG_DOES_DISK_SET_EXIST);
1203 _cmd_messages[12].msgid = (CMD_MSG_TAKE_DISK_SET);
1204 _cmd_messages[12].message = gettext(CMD_MSG_TAKE_DISK_SET);
1205 _cmd_messages[13].msgid = (CMD_MSG_CREATE_THE_DISK_SET);
1206 _cmd_messages[13].message = gettext(CMD_MSG_CREATE_THE_DISK_SET);
1207 _cmd_messages[14].msgid = (CMD_MSG_ADD_DISKS_TO_SET);
1208 _cmd_messages[14].message = gettext(CMD_MSG_ADD_DISKS_TO_SET);
1209 _cmd_messages[15].msgid = (CMD_MSG_FORMAT_SLICES);
1210 _cmd_messages[15].message = gettext(CMD_MSG_FORMAT_SLICES);
1211 _cmd_messages[16].msgid = (CMD_MSG_CREATE);
1212 _cmd_messages[16].message = gettext(CMD_MSG_CREATE);
1213 _cmd_messages[17].msgid = (CMD_MSG_DOES_EXIST);
1214 _cmd_messages[17].message = gettext(CMD_MSG_DOES_EXIST);
1215 _cmd_messages[18].msgid = (CMD_MSG_ADD_SLICES_TO);
1216 _cmd_messages[18].message = gettext(CMD_MSG_ADD_SLICES_TO);
1217 _cmd_messages[19].msgid = (CMD_MSG_ASSOCIATE_WITH_HSP);
1218 _cmd_messages[19].message = gettext(CMD_MSG_ASSOCIATE_WITH_HSP);
1219 _cmd_messages[20].msgid = NULL;
1221 /* Get/set current locale in the "lang" node */
1222 locale = setlocale(LC_MESSAGES, NULL);
1224 /* Add localized <message> elements to stylesheet */
1225 for (i = 0; _cmd_messages[i].msgid != NULL; i++) {
1226 xmlNsPtr ns = xmlNewNs(NULL, NULL, NULL);
1228 xmlNodePtr node = xmlNewTextChild(
1229 root, ns, (xmlChar *)ELEMENT_MESSAGE,
1230 (xmlChar *)_cmd_messages[i].message);
1231 /* Lang attribute */
1232 xmlSetProp(node,
1233 (xmlChar *)ATTR_LANG, (xmlChar *)locale);
1235 /* Message ID attribute */
1236 xmlSetProp(node, (xmlChar *)ATTR_MESSAGEID,
1237 (xmlChar *)_cmd_messages[i].msgid);
1240 if (get_max_verbosity() >= OUTPUT_DEBUG) {
1241 xmlChar *text;
1242 /* Get the text dump */
1243 xmlDocDumpFormatMemory(doc, &text, NULL, 1);
1244 oprintf(OUTPUT_DEBUG,
1245 gettext("Generated message file:\n%s"), text);
1246 xmlFree(text);
1249 return (doc);
1253 * Creates a temporary XML file containing all of the localized
1254 * message strings for the generated command script.
1256 * @param tmpfile
1257 * RETURN: the name of the temporary XML file
1259 * @return 0 on success, non-zero otherwise.
1261 static int
1262 create_localized_message_file(
1263 char **tmpfile)
1265 int error = 0;
1268 * Create temporary file name -- "XXXXXX" is replaced with
1269 * unique char sequence by mkstemp()
1271 *tmpfile = stralloccat(3, "/tmp/", ELEMENT_L10N, "XXXXXX");
1273 if (*tmpfile == NULL) {
1274 volume_set_error(gettext("out of memory"));
1275 error = -1;
1276 } else {
1277 int fildes;
1278 FILE *msgfile = NULL;
1280 /* Open temp file */
1281 if ((fildes = mkstemp(*tmpfile)) != -1) {
1282 msgfile = fdopen(fildes, "w");
1285 if (msgfile == NULL) {
1286 volume_set_error(gettext(
1287 "could not open file for writing: %s"), *tmpfile);
1288 error = -1;
1289 } else {
1291 xmlChar *text;
1292 xmlDocPtr message_doc = create_localized_message_doc();
1293 xmlDocDumpFormatMemory(message_doc, &text, NULL, 1);
1295 if (fprintf(msgfile, "%s", text) < 0) {
1296 volume_set_error(gettext(
1297 "could not create localized message file: %s"),
1298 *tmpfile);
1299 error = -1;
1302 xmlFree(text);
1303 xmlFreeDoc(message_doc);
1306 fclose(msgfile);
1309 return (error);
1313 * Converts the given string into a boolean. The string must be
1314 * either VALID_ATTR_TRUE or VALID_ATTR_FALSE.
1316 * @param str
1317 * the string to convert
1319 * @param bool
1320 * the addr of the boolean_t
1322 * @return 0 if the given string could be converted to a boolean
1323 * non-zero otherwise.
1325 static int
1326 strtobool(
1327 char *str,
1328 boolean_t *value)
1330 int error = 0;
1332 if (strcmp(str, VALID_ATTR_TRUE) == 0) {
1333 *value = B_TRUE;
1334 } else
1336 if (strcmp(str, VALID_ATTR_FALSE) == 0) {
1337 *value = B_FALSE;
1338 } else
1340 error = -1;
1342 return (error);
1346 * Wrapper for oprintf with a OUTPUT_TERSE level of verbosity.
1347 * Provides an fprintf-like syntax to enable use as substitute output
1348 * handler for man of the XML commands.
1350 * @param unused
1351 * unused, in favor of the FILE* passed to
1352 * set_max_verbosity().
1354 * @param fmt
1355 * a printf-style format string
1357 * @return the number of characters output
1359 static int
1360 ofprintf_terse(
1361 void *unused,
1362 char *fmt,
1363 ...)
1365 int ret;
1366 va_list ap;
1368 va_start(ap, fmt);
1369 ret = oprintf_va(OUTPUT_TERSE, fmt, ap);
1370 va_end(ap);
1372 return (ret);
1376 * Wrapper for oprintf with a OUTPUT_VERBOSE level of verbosity.
1377 * Provides an fprintf-like syntax to enable use as substitute output
1378 * handler for man of the XML commands.
1380 * @param unused
1381 * unused, in favor of the FILE* passed to
1382 * set_max_verbosity().
1384 * @param fmt
1385 * a printf-style format string
1387 * @return the number of characters output
1389 static int
1390 ofprintf_verbose(
1391 void *unused,
1392 char *fmt,
1393 ...)
1395 int ret;
1396 va_list ap;
1398 va_start(ap, fmt);
1399 ret = oprintf_va(OUTPUT_VERBOSE, fmt, ap);
1400 va_end(ap);
1402 return (ret);
1406 * ******************************************************************
1408 * XML attribute validators/mutators
1410 * These functions convert the given XML attribute string to the
1411 * appropriate data type, and then pass it on to the appropriate
1412 * devconfig_t mutator. A non-zero status is returned if the given
1413 * string could not be converted or was invalid.
1415 * ******************************************************************
1419 * Validate and set the size attribute in the given volume
1420 * devconfig_t.
1422 * @param volume
1423 * the devconfig_t in which to set the size
1425 * @param attr
1426 * the name of the XML attribute
1428 * @param value
1429 * the value of the XML attribute
1431 * @return 0 on success, non-zero otherwise.
1433 static int
1434 validate_set_size(
1435 devconfig_t *volume,
1436 char *attr,
1437 char *value)
1439 int error;
1440 uint64_t size = 0;
1442 /* Convert size string to bytes */
1443 if ((error = sizestr_to_bytes(value, &size, size_units)) != 0) {
1444 return (error);
1447 /* Set size in volume */
1448 return (devconfig_set_size(volume, size));
1452 * Validate and set the size_in_blocks attribute in the given slice
1453 * devconfig_t.
1455 * @param volume
1456 * the devconfig_t in which to set the size_in_blocks
1458 * @param attr
1459 * the name of the XML attribute
1461 * @param value
1462 * the value of the XML attribute
1464 * @return 0 on success, non-zero otherwise.
1466 static int
1467 validate_set_size_in_blocks(
1468 devconfig_t *slice,
1469 char *attr,
1470 char *value)
1472 long long size;
1474 /* Convert string to long long */
1475 if (sscanf(value, "%lld", &size) != 1) {
1476 volume_set_error(gettext("%s: invalid size in blocks"), value);
1477 return (-1);
1480 /* Set the number of submirrors in the slice */
1481 return (devconfig_set_size_in_blocks(slice, (uint64_t)size));
1485 * Validate and set the name attribute in the given diskset
1486 * devconfig_t.
1488 * @param volume
1489 * the devconfig_t in which to set the name
1491 * @param attr
1492 * the name of the XML attribute
1494 * @param name
1495 * the value of the XML attribute
1497 * @return 0 on success, non-zero otherwise.
1499 static int
1500 validate_set_diskset_name(
1501 devconfig_t *diskset,
1502 char *attr,
1503 char *name)
1505 return (devconfig_set_diskset_name(diskset, name));
1509 * Validate and add the given name to the list of available devices in
1510 * the given volume devconfig_t.
1512 * @param device
1513 * the devconfig_t whose available device list to modify
1515 * @param attr
1516 * the name of the XML attribute
1518 * @param name
1519 * the value of the XML attribute
1521 * @return 0 on success, non-zero otherwise.
1523 static int
1524 validate_add_available_name(
1525 devconfig_t *device,
1526 char *attr,
1527 char *name)
1529 char **available;
1531 /* Get available devices for this device */
1532 available = devconfig_get_available(device);
1534 /* Try to add name to array via realloc */
1535 if ((available = append_to_string_array(available, name)) == NULL) {
1536 return (ENOMEM);
1539 /* Set available devices in the device */
1540 devconfig_set_available(device, available);
1542 return (0);
1546 * Validate and add the given name to the list of unavailable devices
1547 * in the given volume devconfig_t.
1549 * @param device
1550 * the devconfig_t whose unavailable device list to modify
1552 * @param attr
1553 * the name of the XML attribute
1555 * @param name
1556 * the value of the XML attribute
1558 * @return 0 on success, non-zero otherwise.
1560 static int
1561 validate_add_unavailable_name(
1562 devconfig_t *device,
1563 char *attr,
1564 char *name)
1566 char **unavailable;
1568 /* Get unavailable devices for this device */
1569 unavailable = devconfig_get_unavailable(device);
1571 /* Try to add name to array via realloc */
1572 if ((unavailable = append_to_string_array(unavailable, name)) == NULL) {
1573 return (ENOMEM);
1576 /* Set unavailable devices in the device */
1577 devconfig_set_unavailable(device, unavailable);
1579 return (0);
1583 * Validate and set the name attribute in the given hsp devconfig_t.
1585 * @param volume
1586 * the devconfig_t in which to set the name
1588 * @param attr
1589 * the name of the XML attribute
1591 * @param name
1592 * the value of the XML attribute
1594 * @return 0 on success, non-zero otherwise.
1596 static int
1597 validate_set_hsp_name(
1598 devconfig_t *hsp,
1599 char *attr,
1600 char *name)
1602 return (devconfig_set_hsp_name(hsp, name));
1606 * Validate and set the name attribute in the given disk devconfig_t.
1608 * @param volume
1609 * the devconfig_t in which to set the name
1611 * @param attr
1612 * the name of the XML attribute
1614 * @param name
1615 * the value of the XML attribute
1617 * @return 0 on success, non-zero otherwise.
1619 static int
1620 validate_set_disk_name(
1621 devconfig_t *disk,
1622 char *attr,
1623 char *name)
1625 return (devconfig_set_name(disk, name));
1629 * Validate and set the name attribute in the given slice devconfig_t.
1631 * @param volume
1632 * the devconfig_t in which to set the name
1634 * @param attr
1635 * the name of the XML attribute
1637 * @param name
1638 * the value of the XML attribute
1640 * @return 0 on success, non-zero otherwise.
1642 static int
1643 validate_set_slice_name(
1644 devconfig_t *slice,
1645 char *attr,
1646 char *name)
1648 return (devconfig_set_name(slice, name));
1652 * Validate and set the start_block attribute in the given slice
1653 * devconfig_t.
1655 * @param volume
1656 * the devconfig_t in which to set the start_block
1658 * @param attr
1659 * the name of the XML attribute
1661 * @param value
1662 * the value of the XML attribute
1664 * @return 0 on success, non-zero otherwise.
1666 static int
1667 validate_set_slice_start_block(
1668 devconfig_t *slice,
1669 char *attr,
1670 char *value)
1672 long long startsector;
1674 /* Convert string to long long */
1675 if (sscanf(value, "%lld", &startsector) != 1) {
1676 volume_set_error(gettext("%s: invalid start sector"), value);
1677 return (-1);
1680 /* Set the number of submirrors in the slice */
1681 return (devconfig_set_slice_start_block(slice, (uint64_t)startsector));
1685 * Validate and set the name attribute in the given volume
1686 * devconfig_t.
1688 * @param volume
1689 * the devconfig_t in which to set the name
1691 * @param attr
1692 * the name of the XML attribute
1694 * @param name
1695 * the value of the XML attribute
1697 * @return 0 on success, non-zero otherwise.
1699 static int
1700 validate_set_volume_name(
1701 devconfig_t *volume,
1702 char *attr,
1703 char *name)
1705 return (devconfig_set_volume_name(volume, name));
1709 * Validate and set the interlace attribute in the given stripe
1710 * devconfig_t.
1712 * @param volume
1713 * the devconfig_t in which to set the interlace
1715 * @param attr
1716 * the name of the XML attribute
1718 * @param value
1719 * the value of the XML attribute
1721 * @return 0 on success, non-zero otherwise.
1723 static int
1724 validate_set_stripe_interlace(
1725 devconfig_t *stripe,
1726 char *attr,
1727 char *value)
1729 int error;
1730 uint64_t interlace = 0;
1732 /* Convert interlace string to bytes */
1733 if ((error = sizestr_to_bytes(
1734 value, &interlace, interlace_units)) != 0) {
1735 return (error);
1738 /* Set interlace in stripe */
1739 return (devconfig_set_stripe_interlace(stripe, interlace));
1743 * Validate and set the mincomp attribute in the given stripe
1744 * devconfig_t.
1746 * @param volume
1747 * the devconfig_t in which to set the mincomp
1749 * @param attr
1750 * the name of the XML attribute
1752 * @param value
1753 * the value of the XML attribute
1755 * @return 0 on success, non-zero otherwise.
1757 static int
1758 validate_set_stripe_mincomp(
1759 devconfig_t *stripe,
1760 char *attr,
1761 char *value)
1763 uint16_t mincomp;
1765 /* Convert string to a uint16_t */
1766 if (str_to_uint16(value, &mincomp) != 0) {
1767 volume_set_error(
1768 gettext("invalid minimum stripe components (%s): %s"),
1769 attr, value);
1770 return (-1);
1773 /* Set in stripe */
1774 return (devconfig_set_stripe_mincomp(stripe, mincomp));
1778 * Validate and set the maxcomp attribute in the given stripe
1779 * devconfig_t.
1781 * @param volume
1782 * the devconfig_t in which to set the maxcomp
1784 * @param attr
1785 * the name of the XML attribute
1787 * @param value
1788 * the value of the XML attribute
1790 * @return 0 on success, non-zero otherwise.
1792 static int
1793 validate_set_stripe_maxcomp(
1794 devconfig_t *stripe,
1795 char *attr,
1796 char *value)
1798 uint16_t maxcomp;
1800 /* Convert string to a uint16_t */
1801 if (str_to_uint16(value, &maxcomp) != 0) {
1802 volume_set_error(
1803 gettext("invalid maximum stripe components (%s): %s"),
1804 attr, value);
1805 return (-1);
1808 /* Set in stripe */
1809 return (devconfig_set_stripe_maxcomp(stripe, maxcomp));
1813 * Validate and set the usehsp attribute in the given volume
1814 * devconfig_t.
1816 * @param volume
1817 * the devconfig_t in which to set the usehsp
1819 * @param attr
1820 * the name of the XML attribute
1822 * @param value
1823 * the value of the XML attribute
1825 * @return 0 on success, non-zero otherwise.
1827 static int
1828 validate_set_volume_usehsp(
1829 devconfig_t *volume,
1830 char *attr,
1831 char *value)
1833 boolean_t usehsp;
1835 /* Get boolean value */
1836 if (strtobool(value, &usehsp) != 0) {
1837 volume_set_error(
1838 gettext("%s: invalid boolean value for \"%s\" attribute"),
1839 value, attr);
1840 return (-1);
1843 /* Set in volume */
1844 return (devconfig_set_volume_usehsp(volume, usehsp));
1848 * Validate and set the nsubmirrors attribute in the given mirror
1849 * devconfig_t.
1851 * @param volume
1852 * the devconfig_t in which to set the nsubmirrors
1854 * @param attr
1855 * the name of the XML attribute
1857 * @param value
1858 * the value of the XML attribute
1860 * @return 0 on success, non-zero otherwise.
1862 static int
1863 validate_set_mirror_nsubmirrors(
1864 devconfig_t *mirror,
1865 char *attr,
1866 char *value)
1868 uint16_t nsubmirrors;
1870 /* Convert string to a uint16_t */
1871 if (str_to_uint16(value, &nsubmirrors) != 0) {
1872 volume_set_error(
1873 gettext("invalid number of submirrors (%s): %s"),
1874 attr, value);
1875 return (-1);
1878 /* Set in stripe */
1879 return (devconfig_set_mirror_nsubs(mirror, nsubmirrors));
1883 * Validate and set the read attribute in the given mirror
1884 * devconfig_t.
1886 * @param volume
1887 * the devconfig_t in which to set the read
1889 * @param attr
1890 * the name of the XML attribute
1892 * @param value
1893 * the value of the XML attribute
1895 * @return 0 on success, non-zero otherwise.
1897 static int
1898 validate_set_mirror_read(
1899 devconfig_t *mirror,
1900 char *attr,
1901 char *value)
1903 mirror_read_strategy_t strategy;
1905 if (strcmp(value, VALID_MIRROR_READ_ROUNDROBIN) == 0) {
1906 strategy = MIRROR_READ_ROUNDROBIN;
1907 } else
1909 if (strcmp(value, VALID_MIRROR_READ_GEOMETRIC) == 0) {
1910 strategy = MIRROR_READ_GEOMETRIC;
1911 } else
1913 if (strcmp(value, VALID_MIRROR_READ_FIRST) == 0) {
1914 strategy = MIRROR_READ_FIRST;
1915 } else
1918 volume_set_error(gettext("%s: invalid mirror read value"), value);
1919 return (-1);
1922 return (devconfig_set_mirror_read(mirror, strategy));
1926 * Validate and set the write attribute in the given mirror
1927 * devconfig_t.
1929 * @param volume
1930 * the devconfig_t in which to set the write
1932 * @param attr
1933 * the name of the XML attribute
1935 * @param value
1936 * the value of the XML attribute
1938 * @return 0 on success, non-zero otherwise.
1940 static int
1941 validate_set_mirror_write(
1942 devconfig_t *mirror,
1943 char *attr,
1944 char *value)
1946 mirror_write_strategy_t strategy;
1948 if (strcmp(value, VALID_MIRROR_WRITE_PARALLEL) == 0) {
1949 strategy = MIRROR_WRITE_PARALLEL;
1950 } else
1952 if (strcmp(value, VALID_MIRROR_WRITE_SERIAL) == 0) {
1953 strategy = MIRROR_WRITE_SERIAL;
1954 } else
1957 volume_set_error(gettext("%s: invalid mirror write value"), value);
1958 return (-1);
1961 return (devconfig_set_mirror_write(mirror, strategy));
1965 * Validate and set the passnum attribute in the given mirror
1966 * devconfig_t.
1968 * @param volume
1969 * the devconfig_t in which to set the passnum
1971 * @param attr
1972 * the name of the XML attribute
1974 * @param value
1975 * the value of the XML attribute
1977 * @return 0 on success, non-zero otherwise.
1979 static int
1980 validate_set_mirror_passnum(
1981 devconfig_t *mirror,
1982 char *attr,
1983 char *value)
1985 uint16_t passnum;
1987 /* Convert string to a uint16_t */
1988 if (str_to_uint16(value, &passnum) != 0) {
1989 volume_set_error(
1990 gettext("invalid mirror pass number (%s): %s"),
1991 attr, value);
1992 return (-1);
1995 /* Set in stripe */
1996 return (devconfig_set_mirror_pass(mirror, passnum));
2000 * Validate and set the redundancy attribute in the given volume
2001 * devconfig_t.
2003 * @param volume
2004 * the devconfig_t in which to set the redundancy
2006 * @param attr
2007 * the name of the XML attribute
2009 * @param value
2010 * the value of the XML attribute
2012 * @return 0 on success, non-zero otherwise.
2014 static int
2015 validate_set_volume_redundancy(
2016 devconfig_t *volume,
2017 char *attr,
2018 char *value)
2020 uint16_t redundancy;
2022 /* Convert string to a uint16_t */
2023 if (str_to_uint16(value, &redundancy) != 0) {
2024 volume_set_error(
2025 gettext("invalid redundancy level (%s): %s"),
2026 attr, value);
2027 return (-1);
2030 /* Set in stripe */
2031 return (devconfig_set_volume_redundancy_level(volume, redundancy));
2035 * Validate and set the datapaths attribute in the given volume
2036 * devconfig_t.
2038 * @param volume
2039 * the devconfig_t in which to set the datapaths
2041 * @param attr
2042 * the name of the XML attribute
2044 * @param value
2045 * the value of the XML attribute
2047 * @return 0 on success, non-zero otherwise.
2049 static int
2050 validate_set_volume_datapaths(
2051 devconfig_t *volume,
2052 char *attr,
2053 char *value)
2055 uint16_t redundancy;
2057 /* Convert string to a uint16_t */
2058 if (str_to_uint16(value, &redundancy) != 0) {
2059 volume_set_error(
2060 gettext("invalid number of data paths (%s): %s"),
2061 attr, value);
2062 return (-1);
2065 /* Set in stripe */
2066 return (devconfig_set_volume_npaths(volume, redundancy));
2070 * ******************************************************************
2072 * XML attribute accessors/converters
2074 * These functions get a value from the appropriate devconfig_t
2075 * accessor, and then convert it to a string.
2077 * ******************************************************************
2081 * Get, as a string, the value of the name attribute of the given
2082 * devconfig_t. This data must be freed.
2084 * @param device
2085 * the devconfig_t from which to retrieve the name
2087 * @param attr
2088 * the name of the XML attribute
2090 * @param value
2091 * RETURN: the value of the XML attribute
2093 * @return 0 on success, non-zero otherwise.
2095 static int
2096 get_as_string_name(
2097 devconfig_t *device,
2098 char *attr,
2099 char **value)
2101 int error;
2102 char *name;
2104 /* Get name */
2105 if ((error = devconfig_get_name(device, &name)) == 0) {
2106 if ((*value = strdup(name)) == NULL) {
2107 error = ENOMEM;
2111 return (error);
2115 * Get, as a string, the value of the passnum attribute of the given
2116 * mirror devconfig_t. This data must be freed.
2118 * @param device
2119 * the devconfig_t from which to retrieve the passnum
2121 * @param attr
2122 * the name of the XML attribute
2124 * @param value
2125 * RETURN: the value of the XML attribute
2127 * @return 0 on success, non-zero otherwise.
2129 static int
2130 get_as_string_mirror_passnum(
2131 devconfig_t *mirror,
2132 char *attr,
2133 char **value)
2135 int error;
2136 uint16_t passnum;
2138 /* Get mirror pass number */
2139 if ((error = devconfig_get_mirror_pass(mirror, &passnum)) == 0) {
2140 error = ll_to_str(passnum, value);
2143 return (error);
2147 * Get, as a string, the value of the read attribute of the given
2148 * mirror devconfig_t. This data must be freed.
2150 * @param device
2151 * the devconfig_t from which to retrieve the read
2153 * @param attr
2154 * the name of the XML attribute
2156 * @param value
2157 * RETURN: the value of the XML attribute
2159 * @return 0 on success, non-zero otherwise.
2161 static int
2162 get_as_string_mirror_read(
2163 devconfig_t *mirror,
2164 char *attr,
2165 char **value)
2167 int error;
2168 mirror_read_strategy_t read;
2170 /* Get mirror read strategy */
2171 if ((error = devconfig_get_mirror_read(mirror, &read)) == 0) {
2172 if ((*value = strdup(
2173 devconfig_read_strategy_to_str(read))) == NULL) {
2174 error = ENOMEM;
2178 return (error);
2182 * Get, as a string, the value of the write attribute of the given
2183 * mirror devconfig_t. This data must be freed.
2185 * @param device
2186 * the devconfig_t from which to retrieve the write
2188 * @param attr
2189 * the name of the XML attribute
2191 * @param value
2192 * RETURN: the value of the XML attribute
2194 * @return 0 on success, non-zero otherwise.
2196 static int
2197 get_as_string_mirror_write(
2198 devconfig_t *mirror,
2199 char *attr,
2200 char **value)
2202 int error;
2203 mirror_write_strategy_t write;
2205 /* Get mirror write strategy */
2206 if ((error = devconfig_get_mirror_write(mirror, &write)) == 0) {
2207 if ((*value = strdup(
2208 devconfig_write_strategy_to_str(write))) == NULL) {
2209 error = ENOMEM;
2213 return (error);
2217 * Get, as a string, the value of the in_blocks attribute of the given
2218 * device devconfig_t. This data must be freed.
2220 * @param device
2221 * the devconfig_t from which to retrieve the in_blocks
2223 * @param attr
2224 * the name of the XML attribute
2226 * @param value
2227 * RETURN: the value of the XML attribute
2229 * @return 0 on success, non-zero otherwise.
2231 static int
2232 get_as_string_size_in_blocks(
2233 devconfig_t *device,
2234 char *attr,
2235 char **value)
2237 int error;
2238 uint64_t size;
2240 /* Get size in blocks */
2241 if ((error = devconfig_get_size_in_blocks(device, &size)) == 0) {
2242 error = ll_to_str(size, value);
2245 return (error);
2249 * Get, as a string, the value of the start_block attribute of the
2250 * given slice devconfig_t. This data must be freed.
2252 * @param device
2253 * the devconfig_t from which to retrieve the start_block
2255 * @param attr
2256 * the name of the XML attribute
2258 * @param value
2259 * RETURN: the value of the XML attribute
2261 * @return 0 on success, non-zero otherwise.
2263 static int
2264 get_as_string_slice_start_block(
2265 devconfig_t *slice,
2266 char *attr,
2267 char **value)
2269 int error;
2270 uint64_t start;
2272 /* Get slice start block */
2273 if ((error = devconfig_get_slice_start_block(slice, &start)) == 0) {
2274 error = ll_to_str(start, value);
2277 return (error);
2281 * Get, as a string, the value of the interlace attribute of the given
2282 * stripe devconfig_t. This data must be freed.
2284 * @param device
2285 * the devconfig_t from which to retrieve the interlace
2287 * @param attr
2288 * the name of the XML attribute
2290 * @param value
2291 * RETURN: the value of the XML attribute
2293 * @return 0 on success, non-zero otherwise.
2295 static int
2296 get_as_string_stripe_interlace(
2297 devconfig_t *stripe,
2298 char *attr,
2299 char **value)
2301 int error;
2302 uint64_t interlace;
2304 /* Get interlace */
2305 if ((error = devconfig_get_stripe_interlace(
2306 stripe, &interlace)) == 0) {
2307 error = bytes_to_sizestr(interlace, value, interlace_units, B_TRUE);
2310 return (error);