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
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]
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"
34 #include <libxslt/xslt.h>
35 #include <libxslt/xsltInternals.h>
36 #include <libxslt/transform.h>
37 #include <libxslt/xsltutils.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"
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"
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}"
70 #define CMD_MSG_ASSOCIATE_WITH_HSP "Associate {1} {2} with hot spare pool {3}"
73 * ******************************************************************
77 * ******************************************************************
81 * Encapsulates the parsing of an XML attribute
85 /* The name of the attribute */
89 * A function to validate and set the XML attribute value in
90 * the given devconfig_t structure.
93 * the name of the XML attribute
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.
108 * the name of the XML attribute
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
);
120 * Encapsulates the parsing of an XML element
123 /* The name of the element */
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
143 /* The valid XML attributes for this element */
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 * ******************************************************************
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
},
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
},
255 /* <diskset> attributes */
256 static attr_t diskset_attrs
[] = {
257 { ATTR_NAME
, validate_set_diskset_name
, get_as_string_name
},
261 /* <available> attributes */
262 static attr_t available_attrs
[] = {
263 { ATTR_NAME
, validate_add_available_name
, NULL
},
267 /* <unavailable> attributes */
268 static attr_t unavailable_attrs
[] = {
269 { ATTR_NAME
, validate_add_unavailable_name
, NULL
},
273 /* <hsp> attributes */
274 static attr_t hsp_attrs
[] = {
275 { ATTR_NAME
, validate_set_hsp_name
, get_as_string_name
},
279 /* <disk> attributes */
280 static attr_t disk_attrs
[] = {
281 { ATTR_NAME
, validate_set_disk_name
, get_as_string_name
},
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
},
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
},
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
},
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
},
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
},
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
,
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
,
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 * ******************************************************************
387 * ******************************************************************
391 * Initialize the XML parser, setting defaults across all XML
397 /* COMPAT: Do not generate nodes for formatting spaces */
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.
425 xsltCleanupGlobals();
430 * Converts a volume-request XML document into a request_t.
433 * an existing volume-request XML document
436 * RETURN: a new request_t which must be freed via
439 * @return 0 on success, non-zero otherwise.
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
));
467 * Converts a volume-defaults XML document into a defaults_t.
470 * an existing volume-defaults XML document
473 * RETURN: a new defaults_t which must be freed via
476 * @return 0 on success, non-zero otherwise.
481 defaults_t
**defaults
)
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) {
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 */
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 */
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
));
541 * Converts a volume-config XML document into a devconfig_t.
544 * an existing volume-config XML document
547 * RETURN: a new devconfig_t which must be freed via
550 * @return 0 on success, non-zero otherwise.
555 devconfig_t
**config
)
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
);
578 * Converts a devconfig_t into a volume-config XML document.
581 * an existing devconfig_t representing a volume
585 * RETURN: a new volume-config XML document which must be
586 * freed via xmlFreeDoc
588 * @return 0 on success, non-zero otherwise.
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
);
622 * Converts a volume-config XML document into a Bourne shell script.
625 * an existing volume-config XML document
628 * RETURN: a new char* which must be freed
630 * @return 0 on success, non-zero otherwise.
637 char *tmpfile
= NULL
;
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
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) {
677 /* Clear current value of select attribute, if any */
678 xmlChar
*cursel
= xmlGetProp(
679 msgfile_node
, (xmlChar
*)ATTR_SELECT
);
680 if (cursel
!= NULL
) {
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"));
695 /* Set the new value of the select attribute */
696 xmlSetProp(msgfile_node
,
697 (xmlChar
*)ATTR_SELECT
, (xmlChar
*)newsel
);
705 style
= xsltParseStylesheetDoc(xsl_doc
);
711 gettext("could not load stylesheet from %s"),
712 VOLUME_COMMAND_XSL_LOC
);
716 xmlDocPtr result
= xsltApplyStylesheet(style
, doc
, NULL
);
718 if (result
== NULL
) {
720 gettext("could not apply stylesheet to volume-config"));
725 if (xsltSaveResultToString((xmlChar
**)commands
,
726 &length
, result
, style
) == -1) {
731 xsltFreeStylesheet(style
);
734 if (tmpfile
!= NULL
) {
745 * ******************************************************************
749 * ******************************************************************
753 * Sets the external DTD node in the given XML document and then
757 * an existing XML document
760 * the expected root element name of the XML document
763 * the location of the DTD
765 * @return 0 on success, non-zero otherwise.
771 const char *systemID
)
773 xmlValidCtxt context
;
777 volume_set_error(gettext("NULL %s document"), name
);
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
);
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
);
800 gettext("could not create DTD node from %s"), systemID
);
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
);
818 * Converts a devconfig_t into an XML node subject to the rules in
819 * the given element_t array.
822 * the XML node to which to add new XML nodes resulting
823 * from conversion of the given devconfig_t
826 * the element_ts that describe the structure of the XML
827 * document and govern the conversion of the given
831 * the devconfig_t to convert
833 * @return 0 on success, non-zero otherwise.
838 element_t elements
[],
843 xmlNodePtr node
= NULL
;
845 /* Get device type */
846 component_type_t type
;
847 if ((error
= devconfig_get_type(device
, &type
)) != 0) {
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
) {
860 oprintf(OUTPUT_DEBUG
, gettext("Element: %s\n"),
861 devconfig_type_to_str(type
));
863 /* Create the XML node */
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
]);
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 */
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
,
891 /* Attribute is not set in this device */
904 /* Is this node hierarchical? */
905 if (element
->is_hierarchical
== B_FALSE
) {
909 /* Create <available> nodes */
910 array
= devconfig_get_available(device
);
912 for (j
= 0; array
[j
] != NULL
; j
++) {
913 xmlNodePtr child
= xmlNewChild(
914 node
, NULL
, (xmlChar
*)ELEMENT_AVAILABLE
, NULL
);
916 (xmlChar
*)ATTR_NAME
, (xmlChar
*)array
[j
]);
920 /* Create <unavailable> nodes */
921 array
= devconfig_get_unavailable(device
);
923 for (j
= 0; array
[j
] != NULL
; j
++) {
924 xmlNodePtr child
= xmlNewChild(
925 node
, NULL
, (xmlChar
*)ELEMENT_UNAVAILABLE
, NULL
);
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
;
949 /* Are the types the same? */
950 if ((error
= devconfig_get_type(component
, &t
)) != 0) {
953 if (elements
[j
].type
== t
) {
955 error
= devconfig_to_xml(
956 node
, elements
, component
);
967 /* Was this device successfully converted? */
970 gettext("can't convert device of type \"%s\" to XML element"),
971 devconfig_type_to_str(type
));
979 * Converts an XML node into a devconfig_t subject to the rules in
980 * the given element_t array.
983 * the existing XML node to convert
986 * the element_ts that describe the structure of the XML
987 * document and govern the conversion of the given XML
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.
999 element_t elements
[],
1000 devconfig_t
*device
)
1004 /* For each child node... */
1005 for (cur
= cur
->xmlChildrenNode
; cur
!= NULL
; cur
= cur
->next
) {
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) {
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) {
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
));
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) {
1073 /* Get recursive sub-elements */
1074 if ((error
= xml_to_devconfig(
1075 cur
, elements
, component
)) != 0) {
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"),
1099 * Returns 0 if obj2 (devconfig_t *) is a disk set, 1 otherwise.
1102 compare_is_a_diskset(
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.
1115 * the root node to search
1118 * the name of the element type
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.
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) {
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
) {
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
1163 create_localized_message_doc()
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 */
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
) {
1242 /* Get the text dump */
1243 xmlDocDumpFormatMemory(doc
, &text
, NULL
, 1);
1244 oprintf(OUTPUT_DEBUG
,
1245 gettext("Generated message file:\n%s"), text
);
1253 * Creates a temporary XML file containing all of the localized
1254 * message strings for the generated command script.
1257 * RETURN: the name of the temporary XML file
1259 * @return 0 on success, non-zero otherwise.
1262 create_localized_message_file(
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"));
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
);
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"),
1303 xmlFreeDoc(message_doc
);
1313 * Converts the given string into a boolean. The string must be
1314 * either VALID_ATTR_TRUE or VALID_ATTR_FALSE.
1317 * the string to convert
1320 * the addr of the boolean_t
1322 * @return 0 if the given string could be converted to a boolean
1323 * non-zero otherwise.
1332 if (strcmp(str
, VALID_ATTR_TRUE
) == 0) {
1336 if (strcmp(str
, VALID_ATTR_FALSE
) == 0) {
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.
1351 * unused, in favor of the FILE* passed to
1352 * set_max_verbosity().
1355 * a printf-style format string
1357 * @return the number of characters output
1369 ret
= oprintf_va(OUTPUT_TERSE
, fmt
, ap
);
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.
1381 * unused, in favor of the FILE* passed to
1382 * set_max_verbosity().
1385 * a printf-style format string
1387 * @return the number of characters output
1399 ret
= oprintf_va(OUTPUT_VERBOSE
, fmt
, ap
);
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
1423 * the devconfig_t in which to set the size
1426 * the name of the XML attribute
1429 * the value of the XML attribute
1431 * @return 0 on success, non-zero otherwise.
1435 devconfig_t
*volume
,
1442 /* Convert size string to bytes */
1443 if ((error
= sizestr_to_bytes(value
, &size
, size_units
)) != 0) {
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
1456 * the devconfig_t in which to set the size_in_blocks
1459 * the name of the XML attribute
1462 * the value of the XML attribute
1464 * @return 0 on success, non-zero otherwise.
1467 validate_set_size_in_blocks(
1474 /* Convert string to long long */
1475 if (sscanf(value
, "%lld", &size
) != 1) {
1476 volume_set_error(gettext("%s: invalid size in blocks"), value
);
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
1489 * the devconfig_t in which to set the name
1492 * the name of the XML attribute
1495 * the value of the XML attribute
1497 * @return 0 on success, non-zero otherwise.
1500 validate_set_diskset_name(
1501 devconfig_t
*diskset
,
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.
1513 * the devconfig_t whose available device list to modify
1516 * the name of the XML attribute
1519 * the value of the XML attribute
1521 * @return 0 on success, non-zero otherwise.
1524 validate_add_available_name(
1525 devconfig_t
*device
,
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
) {
1539 /* Set available devices in the device */
1540 devconfig_set_available(device
, available
);
1546 * Validate and add the given name to the list of unavailable devices
1547 * in the given volume devconfig_t.
1550 * the devconfig_t whose unavailable device list to modify
1553 * the name of the XML attribute
1556 * the value of the XML attribute
1558 * @return 0 on success, non-zero otherwise.
1561 validate_add_unavailable_name(
1562 devconfig_t
*device
,
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
) {
1576 /* Set unavailable devices in the device */
1577 devconfig_set_unavailable(device
, unavailable
);
1583 * Validate and set the name attribute in the given hsp devconfig_t.
1586 * the devconfig_t in which to set the name
1589 * the name of the XML attribute
1592 * the value of the XML attribute
1594 * @return 0 on success, non-zero otherwise.
1597 validate_set_hsp_name(
1602 return (devconfig_set_hsp_name(hsp
, name
));
1606 * Validate and set the name attribute in the given disk devconfig_t.
1609 * the devconfig_t in which to set the name
1612 * the name of the XML attribute
1615 * the value of the XML attribute
1617 * @return 0 on success, non-zero otherwise.
1620 validate_set_disk_name(
1625 return (devconfig_set_name(disk
, name
));
1629 * Validate and set the name attribute in the given slice devconfig_t.
1632 * the devconfig_t in which to set the name
1635 * the name of the XML attribute
1638 * the value of the XML attribute
1640 * @return 0 on success, non-zero otherwise.
1643 validate_set_slice_name(
1648 return (devconfig_set_name(slice
, name
));
1652 * Validate and set the start_block attribute in the given slice
1656 * the devconfig_t in which to set the start_block
1659 * the name of the XML attribute
1662 * the value of the XML attribute
1664 * @return 0 on success, non-zero otherwise.
1667 validate_set_slice_start_block(
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
);
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
1689 * the devconfig_t in which to set the name
1692 * the name of the XML attribute
1695 * the value of the XML attribute
1697 * @return 0 on success, non-zero otherwise.
1700 validate_set_volume_name(
1701 devconfig_t
*volume
,
1705 return (devconfig_set_volume_name(volume
, name
));
1709 * Validate and set the interlace attribute in the given stripe
1713 * the devconfig_t in which to set the interlace
1716 * the name of the XML attribute
1719 * the value of the XML attribute
1721 * @return 0 on success, non-zero otherwise.
1724 validate_set_stripe_interlace(
1725 devconfig_t
*stripe
,
1730 uint64_t interlace
= 0;
1732 /* Convert interlace string to bytes */
1733 if ((error
= sizestr_to_bytes(
1734 value
, &interlace
, interlace_units
)) != 0) {
1738 /* Set interlace in stripe */
1739 return (devconfig_set_stripe_interlace(stripe
, interlace
));
1743 * Validate and set the mincomp attribute in the given stripe
1747 * the devconfig_t in which to set the mincomp
1750 * the name of the XML attribute
1753 * the value of the XML attribute
1755 * @return 0 on success, non-zero otherwise.
1758 validate_set_stripe_mincomp(
1759 devconfig_t
*stripe
,
1765 /* Convert string to a uint16_t */
1766 if (str_to_uint16(value
, &mincomp
) != 0) {
1768 gettext("invalid minimum stripe components (%s): %s"),
1774 return (devconfig_set_stripe_mincomp(stripe
, mincomp
));
1778 * Validate and set the maxcomp attribute in the given stripe
1782 * the devconfig_t in which to set the maxcomp
1785 * the name of the XML attribute
1788 * the value of the XML attribute
1790 * @return 0 on success, non-zero otherwise.
1793 validate_set_stripe_maxcomp(
1794 devconfig_t
*stripe
,
1800 /* Convert string to a uint16_t */
1801 if (str_to_uint16(value
, &maxcomp
) != 0) {
1803 gettext("invalid maximum stripe components (%s): %s"),
1809 return (devconfig_set_stripe_maxcomp(stripe
, maxcomp
));
1813 * Validate and set the usehsp attribute in the given volume
1817 * the devconfig_t in which to set the usehsp
1820 * the name of the XML attribute
1823 * the value of the XML attribute
1825 * @return 0 on success, non-zero otherwise.
1828 validate_set_volume_usehsp(
1829 devconfig_t
*volume
,
1835 /* Get boolean value */
1836 if (strtobool(value
, &usehsp
) != 0) {
1838 gettext("%s: invalid boolean value for \"%s\" attribute"),
1844 return (devconfig_set_volume_usehsp(volume
, usehsp
));
1848 * Validate and set the nsubmirrors attribute in the given mirror
1852 * the devconfig_t in which to set the nsubmirrors
1855 * the name of the XML attribute
1858 * the value of the XML attribute
1860 * @return 0 on success, non-zero otherwise.
1863 validate_set_mirror_nsubmirrors(
1864 devconfig_t
*mirror
,
1868 uint16_t nsubmirrors
;
1870 /* Convert string to a uint16_t */
1871 if (str_to_uint16(value
, &nsubmirrors
) != 0) {
1873 gettext("invalid number of submirrors (%s): %s"),
1879 return (devconfig_set_mirror_nsubs(mirror
, nsubmirrors
));
1883 * Validate and set the read attribute in the given mirror
1887 * the devconfig_t in which to set the read
1890 * the name of the XML attribute
1893 * the value of the XML attribute
1895 * @return 0 on success, non-zero otherwise.
1898 validate_set_mirror_read(
1899 devconfig_t
*mirror
,
1903 mirror_read_strategy_t strategy
;
1905 if (strcmp(value
, VALID_MIRROR_READ_ROUNDROBIN
) == 0) {
1906 strategy
= MIRROR_READ_ROUNDROBIN
;
1909 if (strcmp(value
, VALID_MIRROR_READ_GEOMETRIC
) == 0) {
1910 strategy
= MIRROR_READ_GEOMETRIC
;
1913 if (strcmp(value
, VALID_MIRROR_READ_FIRST
) == 0) {
1914 strategy
= MIRROR_READ_FIRST
;
1918 volume_set_error(gettext("%s: invalid mirror read value"), value
);
1922 return (devconfig_set_mirror_read(mirror
, strategy
));
1926 * Validate and set the write attribute in the given mirror
1930 * the devconfig_t in which to set the write
1933 * the name of the XML attribute
1936 * the value of the XML attribute
1938 * @return 0 on success, non-zero otherwise.
1941 validate_set_mirror_write(
1942 devconfig_t
*mirror
,
1946 mirror_write_strategy_t strategy
;
1948 if (strcmp(value
, VALID_MIRROR_WRITE_PARALLEL
) == 0) {
1949 strategy
= MIRROR_WRITE_PARALLEL
;
1952 if (strcmp(value
, VALID_MIRROR_WRITE_SERIAL
) == 0) {
1953 strategy
= MIRROR_WRITE_SERIAL
;
1957 volume_set_error(gettext("%s: invalid mirror write value"), value
);
1961 return (devconfig_set_mirror_write(mirror
, strategy
));
1965 * Validate and set the passnum attribute in the given mirror
1969 * the devconfig_t in which to set the passnum
1972 * the name of the XML attribute
1975 * the value of the XML attribute
1977 * @return 0 on success, non-zero otherwise.
1980 validate_set_mirror_passnum(
1981 devconfig_t
*mirror
,
1987 /* Convert string to a uint16_t */
1988 if (str_to_uint16(value
, &passnum
) != 0) {
1990 gettext("invalid mirror pass number (%s): %s"),
1996 return (devconfig_set_mirror_pass(mirror
, passnum
));
2000 * Validate and set the redundancy attribute in the given volume
2004 * the devconfig_t in which to set the redundancy
2007 * the name of the XML attribute
2010 * the value of the XML attribute
2012 * @return 0 on success, non-zero otherwise.
2015 validate_set_volume_redundancy(
2016 devconfig_t
*volume
,
2020 uint16_t redundancy
;
2022 /* Convert string to a uint16_t */
2023 if (str_to_uint16(value
, &redundancy
) != 0) {
2025 gettext("invalid redundancy level (%s): %s"),
2031 return (devconfig_set_volume_redundancy_level(volume
, redundancy
));
2035 * Validate and set the datapaths attribute in the given volume
2039 * the devconfig_t in which to set the datapaths
2042 * the name of the XML attribute
2045 * the value of the XML attribute
2047 * @return 0 on success, non-zero otherwise.
2050 validate_set_volume_datapaths(
2051 devconfig_t
*volume
,
2055 uint16_t redundancy
;
2057 /* Convert string to a uint16_t */
2058 if (str_to_uint16(value
, &redundancy
) != 0) {
2060 gettext("invalid number of data paths (%s): %s"),
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.
2085 * the devconfig_t from which to retrieve the name
2088 * the name of the XML attribute
2091 * RETURN: the value of the XML attribute
2093 * @return 0 on success, non-zero otherwise.
2097 devconfig_t
*device
,
2105 if ((error
= devconfig_get_name(device
, &name
)) == 0) {
2106 if ((*value
= strdup(name
)) == NULL
) {
2115 * Get, as a string, the value of the passnum attribute of the given
2116 * mirror devconfig_t. This data must be freed.
2119 * the devconfig_t from which to retrieve the passnum
2122 * the name of the XML attribute
2125 * RETURN: the value of the XML attribute
2127 * @return 0 on success, non-zero otherwise.
2130 get_as_string_mirror_passnum(
2131 devconfig_t
*mirror
,
2138 /* Get mirror pass number */
2139 if ((error
= devconfig_get_mirror_pass(mirror
, &passnum
)) == 0) {
2140 error
= ll_to_str(passnum
, value
);
2147 * Get, as a string, the value of the read attribute of the given
2148 * mirror devconfig_t. This data must be freed.
2151 * the devconfig_t from which to retrieve the read
2154 * the name of the XML attribute
2157 * RETURN: the value of the XML attribute
2159 * @return 0 on success, non-zero otherwise.
2162 get_as_string_mirror_read(
2163 devconfig_t
*mirror
,
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
) {
2182 * Get, as a string, the value of the write attribute of the given
2183 * mirror devconfig_t. This data must be freed.
2186 * the devconfig_t from which to retrieve the write
2189 * the name of the XML attribute
2192 * RETURN: the value of the XML attribute
2194 * @return 0 on success, non-zero otherwise.
2197 get_as_string_mirror_write(
2198 devconfig_t
*mirror
,
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
) {
2217 * Get, as a string, the value of the in_blocks attribute of the given
2218 * device devconfig_t. This data must be freed.
2221 * the devconfig_t from which to retrieve the in_blocks
2224 * the name of the XML attribute
2227 * RETURN: the value of the XML attribute
2229 * @return 0 on success, non-zero otherwise.
2232 get_as_string_size_in_blocks(
2233 devconfig_t
*device
,
2240 /* Get size in blocks */
2241 if ((error
= devconfig_get_size_in_blocks(device
, &size
)) == 0) {
2242 error
= ll_to_str(size
, value
);
2249 * Get, as a string, the value of the start_block attribute of the
2250 * given slice devconfig_t. This data must be freed.
2253 * the devconfig_t from which to retrieve the start_block
2256 * the name of the XML attribute
2259 * RETURN: the value of the XML attribute
2261 * @return 0 on success, non-zero otherwise.
2264 get_as_string_slice_start_block(
2272 /* Get slice start block */
2273 if ((error
= devconfig_get_slice_start_block(slice
, &start
)) == 0) {
2274 error
= ll_to_str(start
, value
);
2281 * Get, as a string, the value of the interlace attribute of the given
2282 * stripe devconfig_t. This data must be freed.
2285 * the devconfig_t from which to retrieve the interlace
2288 * the name of the XML attribute
2291 * RETURN: the value of the XML attribute
2293 * @return 0 on success, non-zero otherwise.
2296 get_as_string_stripe_interlace(
2297 devconfig_t
*stripe
,
2305 if ((error
= devconfig_get_stripe_interlace(
2306 stripe
, &interlace
)) == 0) {
2307 error
= bytes_to_sizestr(interlace
, value
, interlace_units
, B_TRUE
);