1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
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.
13 *
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]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 #include "xml_convert.h"
30
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"
43
44 /*
45 * IDs for localized messages in the generated command script
46 */
47
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}"
71
72 /*
73 * ******************************************************************
74 *
75 * Data types
76 *
77 * ******************************************************************
78 */
79
80 /*
81 * Encapsulates the parsing of an XML attribute
82 */
83 typedef struct {
84
85 /* The name of the attribute */
86 char *name;
87
88 /*
89 * A function to validate and set the XML attribute value in
90 * the given devconfig_t structure.
91 *
92 * @param name
93 * the name of the XML attribute
94 *
95 * @param value
96 * the value of the XML attribute
97 *
98 * @return 0 if the given value was valid and set
99 * successfully, non-zero otherwise.
100 */
101 int (*validate_set)(devconfig_t *device, char *name, char *value);
102
103 /*
104 * A function to get the XML attribute value in the given
105 * devconfig_t structure.
106 *
107 * @param name
108 * the name of the XML attribute
109 *
110 * @param value
111 * the value of the XML attribute
112 *
113 * @return 0 if the given value was retrieved
114 * successfully, non-zero otherwise.
115 */
116 int (*get_as_string)(devconfig_t *device, char *name, char **value);
117 } attr_t;
118
119 /*
120 * Encapsulates the parsing of an XML element
121 */
122 typedef struct {
123 /* The name of the element */
124 char *name;
125
126 /* The type of element to set in the devconfig_t */
127 component_type_t type;
128
129 /*
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.
133 */
134 boolean_t is_hierarchical;
135
136 /*
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
140 */
141 boolean_t singleton;
142
143 /* The valid XML attributes for this element */
144 attr_t *attributes;
145 } element_t;
146
147 typedef struct {
148 char *msgid;
149 char *message;
150 } l10nmessage_t;
151
152 /*
153 * ******************************************************************
154 *
155 * Function prototypes
156 *
157 * ******************************************************************
158 */
159
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, ...);
173
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);
214
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);
229
230 /*
231 * ******************************************************************
232 *
233 * Data
234 *
235 * ******************************************************************
236 */
237
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}
245 };
246
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}
253 };
254
255 /* <diskset> attributes */
256 static attr_t diskset_attrs[] = {
257 { ATTR_NAME, validate_set_diskset_name, get_as_string_name },
258 { NULL, NULL, NULL }
259 };
260
261 /* <available> attributes */
262 static attr_t available_attrs[] = {
263 { ATTR_NAME, validate_add_available_name, NULL },
264 { NULL, NULL, NULL }
265 };
266
267 /* <unavailable> attributes */
268 static attr_t unavailable_attrs[] = {
269 { ATTR_NAME, validate_add_unavailable_name, NULL },
270 { NULL, NULL, NULL }
271 };
272
273 /* <hsp> attributes */
274 static attr_t hsp_attrs[] = {
275 { ATTR_NAME, validate_set_hsp_name, get_as_string_name },
276 { NULL, NULL, NULL }
277 };
278
279 /* <disk> attributes */
280 static attr_t disk_attrs[] = {
281 { ATTR_NAME, validate_set_disk_name, get_as_string_name },
282 { NULL, NULL, NULL }
283 };
284
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 }
293 };
294
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 }
305 };
306
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 }
313 };
314
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 }
328 };
329
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 }
338 };
339
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 }
353 };
354
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 }
368 };
369
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 }
380 };
381
382 /*
383 * ******************************************************************
384 *
385 * External functions
386 *
387 * ******************************************************************
388 */
389
390 /*
391 * Initialize the XML parser, setting defaults across all XML
392 * routines.
393 */
394 void
init_xml()395 init_xml()
396 {
397 /* COMPAT: Do not generate nodes for formatting spaces */
398 LIBXML_TEST_VERSION
399 xmlKeepBlanksDefault(0);
400
401 /* Turn on line numbers for debugging */
402 xmlLineNumbersDefault(1);
403
404 /* Substitute entities as files are parsed */
405 xmlSubstituteEntitiesDefault(1);
406
407 /* Don't load external entity subsets */
408 xmlLoadExtDtdDefaultValue = 0;
409
410 /* Don't validate against DTD by default */
411 xmlDoValidityCheckingDefaultValue = 0;
412
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;
417 }
418
419 /*
420 * Clean up any remaining structures before exiting.
421 */
422 void
cleanup_xml()423 cleanup_xml()
424 {
425 xsltCleanupGlobals();
426 xmlCleanupParser();
427 }
428
429 /*
430 * Converts a volume-request XML document into a request_t.
431 *
432 * @param doc
433 * an existing volume-request XML document
434 *
435 * @param request
436 * RETURN: a new request_t which must be freed via
437 * free_request
438 *
439 * @return 0 on success, non-zero otherwise.
440 */
441 int
xml_to_request(xmlDocPtr doc,request_t ** request)442 xml_to_request(
443 xmlDocPtr doc,
444 request_t **request)
445 {
446 int error = 0;
447
448 *request = NULL;
449
450 /* Validate doc against known DTD */
451 if ((error = validate_doc(
452 doc, ELEMENT_VOLUMEREQUEST, VOLUME_REQUEST_DTD_LOC)) == 0) {
453
454 /* Create a request */
455 if ((error = new_request(request)) == 0) {
456
457 /* Convert the XML doc into a request_t */
458 error = xml_to_devconfig(xmlDocGetRootElement(doc),
459 request_elements, request_get_diskset_req(*request));
460 }
461 }
462
463 return (error);
464 }
465
466 /*
467 * Converts a volume-defaults XML document into a defaults_t.
468 *
469 * @param doc
470 * an existing volume-defaults XML document
471 *
472 * @param defaults
473 * RETURN: a new defaults_t which must be freed via
474 * free_defaults
475 *
476 * @return 0 on success, non-zero otherwise.
477 */
478 int
xml_to_defaults(xmlDocPtr doc,defaults_t ** defaults)479 xml_to_defaults(
480 xmlDocPtr doc,
481 defaults_t **defaults)
482 {
483 int error = 0;
484
485 *defaults = NULL;
486
487 /* Validate doc against known DTD */
488 if ((error = validate_doc(doc, ELEMENT_VOLUMEDEFAULTS,
489 VOLUME_DEFAULTS_DTD_LOC)) == 0) {
490
491 /* Create request defaults */
492 if ((error = new_defaults(defaults)) == 0) {
493
494 devconfig_t *global;
495
496 /* Get defaults for all disk sets */
497 if ((error = defaults_get_diskset_by_name(
498 *defaults, NULL, &global)) == 0) {
499
500 /* Populate the global devconfig_t from the XML doc */
501 if ((error = xml_to_devconfig(xmlDocGetRootElement(doc),
502 default_elements, global)) == 0) {
503
504 /* Get the components of the global devconfig_t */
505 dlist_t *list = devconfig_get_components(global);
506
507 /*
508 * Move all named disk set settings out from
509 * under global settings
510 */
511 /* CONSTANTCONDITION */
512 while (1) {
513 dlist_t *removed = NULL;
514 devconfig_t *component;
515
516 /* Remove named disk set from under global */
517 list = dlist_remove_equivalent_item(
518 list, NULL, compare_is_a_diskset, &removed);
519
520 if (removed == NULL) {
521 /* No named disk set found */
522 break;
523 }
524
525 component = removed->obj;
526
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));
531 }
532 }
533 }
534 }
535 }
536
537 return (error);
538 }
539
540 /*
541 * Converts a volume-config XML document into a devconfig_t.
542 *
543 * @param doc
544 * an existing volume-config XML document
545 *
546 * @param config
547 * RETURN: a new devconfig_t which must be freed via
548 * free_devconfig
549 *
550 * @return 0 on success, non-zero otherwise.
551 */
552 int
xml_to_config(xmlDocPtr doc,devconfig_t ** config)553 xml_to_config(
554 xmlDocPtr doc,
555 devconfig_t **config)
556 {
557 int error = 0;
558
559 *config = NULL;
560
561 /* Validate doc against known DTD */
562 if ((error = validate_doc(
563 doc, ELEMENT_VOLUMECONFIG, VOLUME_CONFIG_DTD_LOC)) == 0) {
564
565 /* Create a devconfig_t */
566 if ((error = new_devconfig(config, TYPE_DISKSET)) == 0) {
567
568 /* Populate the devconfig_t from the XML doc */
569 error = xml_to_devconfig(
570 xmlDocGetRootElement(doc), config_elements, *config);
571 }
572 }
573
574 return (error);
575 }
576
577 /*
578 * Converts a devconfig_t into a volume-config XML document.
579 *
580 * @param config
581 * an existing devconfig_t representing a volume
582 * configuration.
583 *
584 * @param doc
585 * RETURN: a new volume-config XML document which must be
586 * freed via xmlFreeDoc
587 *
588 * @return 0 on success, non-zero otherwise.
589 */
590 int
config_to_xml(devconfig_t * config,xmlDocPtr * doc)591 config_to_xml(
592 devconfig_t *config,
593 xmlDocPtr *doc)
594 {
595 xmlNodePtr root;
596 int error = 0;
597
598 /* Create the XML document */
599 *doc = xmlNewDoc((xmlChar *)"1.0");
600
601 /* Create the root node */
602 root = xmlNewDocNode(
603 *doc, NULL, (xmlChar *)ELEMENT_VOLUMECONFIG, NULL);
604 xmlAddChild((xmlNodePtr)*doc, (xmlNodePtr)root);
605
606 /* Create sub-nodes from the config devconfig_t */
607 if ((error = devconfig_to_xml(root, config_elements, config)) == 0) {
608
609 /* Add DTD node and validate */
610 error = validate_doc(
611 *doc, ELEMENT_VOLUMECONFIG, VOLUME_CONFIG_DTD_LOC);
612 }
613
614 if (error) {
615 xmlFreeDoc(*doc);
616 }
617
618 return (error);
619 }
620
621 /*
622 * Converts a volume-config XML document into a Bourne shell script.
623 *
624 * @param doc
625 * an existing volume-config XML document
626 *
627 * @param commands
628 * RETURN: a new char* which must be freed
629 *
630 * @return 0 on success, non-zero otherwise.
631 */
632 int
xml_to_commands(xmlDocPtr doc,char ** commands)633 xml_to_commands(
634 xmlDocPtr doc,
635 char **commands)
636 {
637 char *tmpfile = NULL;
638 int error = 0;
639 xsltStylesheetPtr style = NULL;
640
641 /* Read in XSL stylesheet as a normal XML document */
642 xmlDocPtr xsl_doc = xmlSAXParseFile((xmlSAXHandlerPtr)
643 &xmlDefaultSAXHandler, VOLUME_COMMAND_XSL_LOC, 0);
644
645 if (xsl_doc != NULL && xsl_doc->xmlChildrenNode != NULL) {
646
647 /*
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.
651 */
652 xmlNodePtr msgfile_node = xml_find_node(
653 xmlDocGetRootElement(xsl_doc), (xmlChar *)ELEMENT_VARIABLE,
654 (xmlChar *)NAME_L10N_MESSAGE_FILE);
655
656 /*
657 * Find the "lang" node. This is where we'll set the
658 * current locale.
659 */
660 xmlNodePtr lang_node = xml_find_node(xmlDocGetRootElement(xsl_doc),
661 (xmlChar *)ELEMENT_PARAM, (xmlChar *)NAME_LANG);
662
663 /*
664 * Ignore if the nodes are not found -- the script
665 * will default to the C locale.
666 */
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);
671
672 /* Write localized messages to a temporary file */
673 if ((error = create_localized_message_file(&tmpfile)) == 0) {
674
675 char *newsel;
676
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);
682 }
683
684 /*
685 * The select attribute calls the XSLT function
686 * document() to load an external XML file
687 */
688 newsel = stralloccat(3, "document('", tmpfile, "')");
689
690 if (newsel == NULL) {
691 volume_set_error(gettext("out of memory"));
692 error = -1;
693 } else {
694
695 /* Set the new value of the select attribute */
696 xmlSetProp(msgfile_node,
697 (xmlChar *)ATTR_SELECT, (xmlChar *)newsel);
698
699 free(newsel);
700 }
701 }
702 }
703
704 if (error == 0) {
705 style = xsltParseStylesheetDoc(xsl_doc);
706 }
707 }
708
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 {
715
716 xmlDocPtr result = xsltApplyStylesheet(style, doc, NULL);
717
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;
724
725 if (xsltSaveResultToString((xmlChar **)commands,
726 &length, result, style) == -1) {
727 error = ENOMEM;
728 }
729 }
730
731 xsltFreeStylesheet(style);
732 }
733
734 if (tmpfile != NULL) {
735 /* Ignore failure */
736 unlink(tmpfile);
737
738 free(tmpfile);
739 }
740
741 return (error);
742 }
743
744 /*
745 * ******************************************************************
746 *
747 * Static functions
748 *
749 * ******************************************************************
750 */
751
752 /*
753 * Sets the external DTD node in the given XML document and then
754 * validates it.
755 *
756 * @param doc
757 * an existing XML document
758 *
759 * @param name
760 * the expected root element name of the XML document
761 *
762 * @param systemID
763 * the location of the DTD
764 *
765 * @return 0 on success, non-zero otherwise.
766 */
767 static int
validate_doc(xmlDocPtr doc,const char * name,const char * systemID)768 validate_doc(
769 xmlDocPtr doc,
770 const char *name,
771 const char *systemID)
772 {
773 xmlValidCtxt context;
774 xmlDtdPtr dtd;
775
776 if (doc == NULL) {
777 volume_set_error(gettext("NULL %s document"), name);
778 return (-1);
779 }
780
781 /*
782 * Assume that we can't trust any DTD but our own.
783 */
784
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);
791 }
792
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);
802 }
803
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);
812 }
813
814 return (0);
815 }
816
817 /*
818 * Converts a devconfig_t into an XML node subject to the rules in
819 * the given element_t array.
820 *
821 * @param parent
822 * the XML node to which to add new XML nodes resulting
823 * from conversion of the given devconfig_t
824 *
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
829 *
830 * @param device
831 * the devconfig_t to convert
832 *
833 * @return 0 on success, non-zero otherwise.
834 */
835 static int
devconfig_to_xml(xmlNodePtr parent,element_t elements[],devconfig_t * device)836 devconfig_to_xml(
837 xmlNodePtr parent,
838 element_t elements[],
839 devconfig_t *device)
840 {
841 int i;
842 int error = 0;
843 xmlNodePtr node = NULL;
844
845 /* Get device type */
846 component_type_t type;
847 if ((error = devconfig_get_type(device, &type)) != 0) {
848 return (error);
849 }
850
851 /* Search for this element definition */
852 for (i = 0; elements[i].name != NULL; i++) {
853 element_t *element = &(elements[i]);
854
855 if (element->type == type) {
856 int j;
857 char **array;
858 dlist_t *components;
859
860 oprintf(OUTPUT_DEBUG, gettext("Element: %s\n"),
861 devconfig_type_to_str(type));
862
863 /* Create the XML node */
864 node = xmlNewChild(
865 parent, NULL, (xmlChar *)element->name, NULL);
866
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;
871
872 /* Is there a valid accessor for this attribute? */
873 if (attribute->get_as_string != NULL) {
874
875 /* Get the attribute value from the device */
876 switch (error = attribute->get_as_string(
877 device, attribute->name, &value)) {
878
879 /* Attribute is set in this device */
880 case 0:
881 oprintf(OUTPUT_DEBUG, " %s: %s\n",
882 attribute->name, value);
883
884 /* Set the value in the XML node */
885 xmlSetProp(node, (uchar_t *)attribute->name,
886 (uchar_t *)value);
887 free(value);
888
889 /* FALLTHROUGH */
890
891 /* Attribute is not set in this device */
892 case ERR_ATTR_UNSET:
893
894 error = 0;
895 break;
896
897 /* Error */
898 default:
899 return (error);
900 }
901 }
902 }
903
904 /* Is this node hierarchical? */
905 if (element->is_hierarchical == B_FALSE) {
906 node = parent;
907 }
908
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]);
917 }
918 }
919
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]);
928 }
929 }
930
931 /*
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).
936 */
937
938 /* For each element type... */
939 for (j = 0; elements[j].name != NULL; j++) {
940
941 /* For each component of this device... */
942 for (components = devconfig_get_components(device);
943 components != NULL && error == 0;
944 components = components->next) {
945
946 devconfig_t *component = (devconfig_t *)components->obj;
947 component_type_t t;
948
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);
957 }
958 }
959 }
960 }
961
962 /* Element found */
963 break;
964 }
965 }
966
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;
973 }
974
975 return (error);
976 }
977
978 /*
979 * Converts an XML node into a devconfig_t subject to the rules in
980 * the given element_t array.
981 *
982 * @param cure
983 * the existing XML node to convert
984 *
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
989 *
990 * @param device
991 * the devconfig_t node to which to add new devconfig_ts
992 * resulting from conversion of the given XML node
993 *
994 * @return 0 on success, non-zero otherwise.
995 */
996 static int
xml_to_devconfig(xmlNodePtr cur,element_t elements[],devconfig_t * device)997 xml_to_devconfig(
998 xmlNodePtr cur,
999 element_t elements[],
1000 devconfig_t *device)
1001 {
1002 int error = 0;
1003
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;
1008
1009 /* Search for this element definition */
1010 for (i = 0; elements[i].name != NULL; i++) {
1011 element_t *element = &(elements[i]);
1012
1013 if (xmlStrcmp(cur->name, (xmlChar *)element->name) == 0) {
1014 int j;
1015 devconfig_t *component = NULL;
1016
1017 /* Flag that this element has been parsed */
1018 parsed_elem = B_TRUE;
1019
1020 oprintf(OUTPUT_DEBUG, gettext("line %d: Element <%s>\n"),
1021 XML_GET_LINE(cur), cur->name);
1022
1023 /* Should a new device be created for this element? */
1024 if (element->is_hierarchical == B_TRUE) {
1025
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);
1030 }
1031
1032 if (component == NULL) {
1033 oprintf(OUTPUT_DEBUG,
1034 gettext("Creating new device\n"));
1035
1036 /* Create device of this type */
1037 if ((error = new_devconfig(
1038 &component, element->type)) != 0) {
1039 return (error);
1040 }
1041
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));
1046 }
1047 } else {
1048 component = device;
1049 }
1050
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]);
1054
1055 /* Get the value of this attribute */
1056 char *value = (char *)
1057 xmlGetProp(cur, (xmlChar *)attribute->name);
1058
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);
1064
1065 /* Set this value in the device */
1066 if ((error = attribute->validate_set(
1067 component, attribute->name, value)) != 0) {
1068 return (error);
1069 }
1070 }
1071 }
1072
1073 /* Get recursive sub-elements */
1074 if ((error = xml_to_devconfig(
1075 cur, elements, component)) != 0) {
1076 return (error);
1077 }
1078
1079 /* Element found */
1080 break;
1081 }
1082 }
1083
1084
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) {
1089
1090 oprintf(OUTPUT_DEBUG, gettext("Element <%s> NOT PARSED!!!\n"),
1091 cur->name);
1092 }
1093 }
1094
1095 return (0);
1096 }
1097
1098 /*
1099 * Returns 0 if obj2 (devconfig_t *) is a disk set, 1 otherwise.
1100 */
1101 static int
compare_is_a_diskset(void * obj1,void * obj2)1102 compare_is_a_diskset(
1103 void *obj1,
1104 void *obj2)
1105 {
1106 return (devconfig_isA(
1107 (devconfig_t *)obj2, TYPE_DISKSET) == B_TRUE ? 0 : 1);
1108 }
1109
1110 /*
1111 * Recursively searches the given xmlNodePtr for an element of the
1112 * specified type and name.
1113 *
1114 * @param node
1115 * the root node to search
1116 *
1117 * @param element
1118 * the name of the element type
1119 *
1120 * @param name
1121 * the value of the name attribute
1122 *
1123 * @return a valid xmlNodePtr if an element of the specified
1124 * type and name was found, NULL otherwise.
1125 */
1126 static xmlNodePtr
xml_find_node(xmlNodePtr node,xmlChar * element,xmlChar * name)1127 xml_find_node(
1128 xmlNodePtr node,
1129 xmlChar *element,
1130 xmlChar *name)
1131 {
1132 xmlNodePtr child;
1133
1134 /* Is the element the right type? */
1135 if (xmlStrcmp(element, node->name) == 0 &&
1136
1137 /* Does this element's name attribute match? */
1138 xmlStrcmp(name, xmlGetProp(node, (xmlChar *)ATTR_NAME)) == 0) {
1139
1140 return (node);
1141 }
1142
1143 /* Check child nodes */
1144 for (child = node->xmlChildrenNode; child != NULL;
1145 child = child->next) {
1146 xmlNodePtr found = xml_find_node(child, element, name);
1147
1148 if (found != NULL) {
1149 return (found);
1150 }
1151 }
1152
1153 return (NULL);
1154 }
1155
1156 /*
1157 * Creates an XML document containing all of the localized message
1158 * strings for the generated command script.
1159 *
1160 * @return a xmlDocPtr which must be freed via xmlFreeDoc
1161 */
1162 static xmlDocPtr
create_localized_message_doc()1163 create_localized_message_doc()
1164 {
1165 int i;
1166 char *locale;
1167 xmlDocPtr doc;
1168 xmlNodePtr root;
1169 l10nmessage_t _cmd_messages[21];
1170
1171 /* Create the XML document */
1172 doc = xmlNewDoc((xmlChar *)"1.0");
1173
1174 /* Create the root node */
1175 root = xmlNewDocNode(
1176 doc, NULL, (xmlChar *)ELEMENT_L10N, NULL);
1177 xmlAddChild((xmlNodePtr) doc, (xmlNodePtr)root);
1178
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;
1220
1221 /* Get/set current locale in the "lang" node */
1222 locale = setlocale(LC_MESSAGES, NULL);
1223
1224 /* Add localized <message> elements to stylesheet */
1225 for (i = 0; _cmd_messages[i].msgid != NULL; i++) {
1226 xmlNsPtr ns = xmlNewNs(NULL, NULL, NULL);
1227
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);
1234
1235 /* Message ID attribute */
1236 xmlSetProp(node, (xmlChar *)ATTR_MESSAGEID,
1237 (xmlChar *)_cmd_messages[i].msgid);
1238 }
1239
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);
1247 }
1248
1249 return (doc);
1250 }
1251
1252 /*
1253 * Creates a temporary XML file containing all of the localized
1254 * message strings for the generated command script.
1255 *
1256 * @param tmpfile
1257 * RETURN: the name of the temporary XML file
1258 *
1259 * @return 0 on success, non-zero otherwise.
1260 */
1261 static int
create_localized_message_file(char ** tmpfile)1262 create_localized_message_file(
1263 char **tmpfile)
1264 {
1265 int error = 0;
1266
1267 /*
1268 * Create temporary file name -- "XXXXXX" is replaced with
1269 * unique char sequence by mkstemp()
1270 */
1271 *tmpfile = stralloccat(3, "/tmp/", ELEMENT_L10N, "XXXXXX");
1272
1273 if (*tmpfile == NULL) {
1274 volume_set_error(gettext("out of memory"));
1275 error = -1;
1276 } else {
1277 int fildes;
1278 FILE *msgfile = NULL;
1279
1280 /* Open temp file */
1281 if ((fildes = mkstemp(*tmpfile)) != -1) {
1282 msgfile = fdopen(fildes, "w");
1283 }
1284
1285 if (msgfile == NULL) {
1286 volume_set_error(gettext(
1287 "could not open file for writing: %s"), *tmpfile);
1288 error = -1;
1289 } else {
1290
1291 xmlChar *text;
1292 xmlDocPtr message_doc = create_localized_message_doc();
1293 xmlDocDumpFormatMemory(message_doc, &text, NULL, 1);
1294
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;
1300 }
1301
1302 xmlFree(text);
1303 xmlFreeDoc(message_doc);
1304 }
1305
1306 fclose(msgfile);
1307 }
1308
1309 return (error);
1310 }
1311
1312 /*
1313 * Converts the given string into a boolean. The string must be
1314 * either VALID_ATTR_TRUE or VALID_ATTR_FALSE.
1315 *
1316 * @param str
1317 * the string to convert
1318 *
1319 * @param bool
1320 * the addr of the boolean_t
1321 *
1322 * @return 0 if the given string could be converted to a boolean
1323 * non-zero otherwise.
1324 */
1325 static int
strtobool(char * str,boolean_t * value)1326 strtobool(
1327 char *str,
1328 boolean_t *value)
1329 {
1330 int error = 0;
1331
1332 if (strcmp(str, VALID_ATTR_TRUE) == 0) {
1333 *value = B_TRUE;
1334 } else
1335
1336 if (strcmp(str, VALID_ATTR_FALSE) == 0) {
1337 *value = B_FALSE;
1338 } else
1339
1340 error = -1;
1341
1342 return (error);
1343 }
1344
1345 /*
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.
1349 *
1350 * @param unused
1351 * unused, in favor of the FILE* passed to
1352 * set_max_verbosity().
1353 *
1354 * @param fmt
1355 * a printf-style format string
1356 *
1357 * @return the number of characters output
1358 */
1359 static int
ofprintf_terse(void * unused,char * fmt,...)1360 ofprintf_terse(
1361 void *unused,
1362 char *fmt,
1363 ...)
1364 {
1365 int ret;
1366 va_list ap;
1367
1368 va_start(ap, fmt);
1369 ret = oprintf_va(OUTPUT_TERSE, fmt, ap);
1370 va_end(ap);
1371
1372 return (ret);
1373 }
1374
1375 /*
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.
1379 *
1380 * @param unused
1381 * unused, in favor of the FILE* passed to
1382 * set_max_verbosity().
1383 *
1384 * @param fmt
1385 * a printf-style format string
1386 *
1387 * @return the number of characters output
1388 */
1389 static int
ofprintf_verbose(void * unused,char * fmt,...)1390 ofprintf_verbose(
1391 void *unused,
1392 char *fmt,
1393 ...)
1394 {
1395 int ret;
1396 va_list ap;
1397
1398 va_start(ap, fmt);
1399 ret = oprintf_va(OUTPUT_VERBOSE, fmt, ap);
1400 va_end(ap);
1401
1402 return (ret);
1403 }
1404
1405 /*
1406 * ******************************************************************
1407 *
1408 * XML attribute validators/mutators
1409 *
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.
1414 *
1415 * ******************************************************************
1416 */
1417
1418 /*
1419 * Validate and set the size attribute in the given volume
1420 * devconfig_t.
1421 *
1422 * @param volume
1423 * the devconfig_t in which to set the size
1424 *
1425 * @param attr
1426 * the name of the XML attribute
1427 *
1428 * @param value
1429 * the value of the XML attribute
1430 *
1431 * @return 0 on success, non-zero otherwise.
1432 */
1433 static int
validate_set_size(devconfig_t * volume,char * attr,char * value)1434 validate_set_size(
1435 devconfig_t *volume,
1436 char *attr,
1437 char *value)
1438 {
1439 int error;
1440 uint64_t size = 0;
1441
1442 /* Convert size string to bytes */
1443 if ((error = sizestr_to_bytes(value, &size, size_units)) != 0) {
1444 return (error);
1445 }
1446
1447 /* Set size in volume */
1448 return (devconfig_set_size(volume, size));
1449 }
1450
1451 /*
1452 * Validate and set the size_in_blocks attribute in the given slice
1453 * devconfig_t.
1454 *
1455 * @param volume
1456 * the devconfig_t in which to set the size_in_blocks
1457 *
1458 * @param attr
1459 * the name of the XML attribute
1460 *
1461 * @param value
1462 * the value of the XML attribute
1463 *
1464 * @return 0 on success, non-zero otherwise.
1465 */
1466 static int
validate_set_size_in_blocks(devconfig_t * slice,char * attr,char * value)1467 validate_set_size_in_blocks(
1468 devconfig_t *slice,
1469 char *attr,
1470 char *value)
1471 {
1472 long long size;
1473
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);
1478 }
1479
1480 /* Set the number of submirrors in the slice */
1481 return (devconfig_set_size_in_blocks(slice, (uint64_t)size));
1482 }
1483
1484 /*
1485 * Validate and set the name attribute in the given diskset
1486 * devconfig_t.
1487 *
1488 * @param volume
1489 * the devconfig_t in which to set the name
1490 *
1491 * @param attr
1492 * the name of the XML attribute
1493 *
1494 * @param name
1495 * the value of the XML attribute
1496 *
1497 * @return 0 on success, non-zero otherwise.
1498 */
1499 static int
validate_set_diskset_name(devconfig_t * diskset,char * attr,char * name)1500 validate_set_diskset_name(
1501 devconfig_t *diskset,
1502 char *attr,
1503 char *name)
1504 {
1505 return (devconfig_set_diskset_name(diskset, name));
1506 }
1507
1508 /*
1509 * Validate and add the given name to the list of available devices in
1510 * the given volume devconfig_t.
1511 *
1512 * @param device
1513 * the devconfig_t whose available device list to modify
1514 *
1515 * @param attr
1516 * the name of the XML attribute
1517 *
1518 * @param name
1519 * the value of the XML attribute
1520 *
1521 * @return 0 on success, non-zero otherwise.
1522 */
1523 static int
validate_add_available_name(devconfig_t * device,char * attr,char * name)1524 validate_add_available_name(
1525 devconfig_t *device,
1526 char *attr,
1527 char *name)
1528 {
1529 char **available;
1530
1531 /* Get available devices for this device */
1532 available = devconfig_get_available(device);
1533
1534 /* Try to add name to array via realloc */
1535 if ((available = append_to_string_array(available, name)) == NULL) {
1536 return (ENOMEM);
1537 }
1538
1539 /* Set available devices in the device */
1540 devconfig_set_available(device, available);
1541
1542 return (0);
1543 }
1544
1545 /*
1546 * Validate and add the given name to the list of unavailable devices
1547 * in the given volume devconfig_t.
1548 *
1549 * @param device
1550 * the devconfig_t whose unavailable device list to modify
1551 *
1552 * @param attr
1553 * the name of the XML attribute
1554 *
1555 * @param name
1556 * the value of the XML attribute
1557 *
1558 * @return 0 on success, non-zero otherwise.
1559 */
1560 static int
validate_add_unavailable_name(devconfig_t * device,char * attr,char * name)1561 validate_add_unavailable_name(
1562 devconfig_t *device,
1563 char *attr,
1564 char *name)
1565 {
1566 char **unavailable;
1567
1568 /* Get unavailable devices for this device */
1569 unavailable = devconfig_get_unavailable(device);
1570
1571 /* Try to add name to array via realloc */
1572 if ((unavailable = append_to_string_array(unavailable, name)) == NULL) {
1573 return (ENOMEM);
1574 }
1575
1576 /* Set unavailable devices in the device */
1577 devconfig_set_unavailable(device, unavailable);
1578
1579 return (0);
1580 }
1581
1582 /*
1583 * Validate and set the name attribute in the given hsp devconfig_t.
1584 *
1585 * @param volume
1586 * the devconfig_t in which to set the name
1587 *
1588 * @param attr
1589 * the name of the XML attribute
1590 *
1591 * @param name
1592 * the value of the XML attribute
1593 *
1594 * @return 0 on success, non-zero otherwise.
1595 */
1596 static int
validate_set_hsp_name(devconfig_t * hsp,char * attr,char * name)1597 validate_set_hsp_name(
1598 devconfig_t *hsp,
1599 char *attr,
1600 char *name)
1601 {
1602 return (devconfig_set_hsp_name(hsp, name));
1603 }
1604
1605 /*
1606 * Validate and set the name attribute in the given disk devconfig_t.
1607 *
1608 * @param volume
1609 * the devconfig_t in which to set the name
1610 *
1611 * @param attr
1612 * the name of the XML attribute
1613 *
1614 * @param name
1615 * the value of the XML attribute
1616 *
1617 * @return 0 on success, non-zero otherwise.
1618 */
1619 static int
validate_set_disk_name(devconfig_t * disk,char * attr,char * name)1620 validate_set_disk_name(
1621 devconfig_t *disk,
1622 char *attr,
1623 char *name)
1624 {
1625 return (devconfig_set_name(disk, name));
1626 }
1627
1628 /*
1629 * Validate and set the name attribute in the given slice devconfig_t.
1630 *
1631 * @param volume
1632 * the devconfig_t in which to set the name
1633 *
1634 * @param attr
1635 * the name of the XML attribute
1636 *
1637 * @param name
1638 * the value of the XML attribute
1639 *
1640 * @return 0 on success, non-zero otherwise.
1641 */
1642 static int
validate_set_slice_name(devconfig_t * slice,char * attr,char * name)1643 validate_set_slice_name(
1644 devconfig_t *slice,
1645 char *attr,
1646 char *name)
1647 {
1648 return (devconfig_set_name(slice, name));
1649 }
1650
1651 /*
1652 * Validate and set the start_block attribute in the given slice
1653 * devconfig_t.
1654 *
1655 * @param volume
1656 * the devconfig_t in which to set the start_block
1657 *
1658 * @param attr
1659 * the name of the XML attribute
1660 *
1661 * @param value
1662 * the value of the XML attribute
1663 *
1664 * @return 0 on success, non-zero otherwise.
1665 */
1666 static int
validate_set_slice_start_block(devconfig_t * slice,char * attr,char * value)1667 validate_set_slice_start_block(
1668 devconfig_t *slice,
1669 char *attr,
1670 char *value)
1671 {
1672 long long startsector;
1673
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);
1678 }
1679
1680 /* Set the number of submirrors in the slice */
1681 return (devconfig_set_slice_start_block(slice, (uint64_t)startsector));
1682 }
1683
1684 /*
1685 * Validate and set the name attribute in the given volume
1686 * devconfig_t.
1687 *
1688 * @param volume
1689 * the devconfig_t in which to set the name
1690 *
1691 * @param attr
1692 * the name of the XML attribute
1693 *
1694 * @param name
1695 * the value of the XML attribute
1696 *
1697 * @return 0 on success, non-zero otherwise.
1698 */
1699 static int
validate_set_volume_name(devconfig_t * volume,char * attr,char * name)1700 validate_set_volume_name(
1701 devconfig_t *volume,
1702 char *attr,
1703 char *name)
1704 {
1705 return (devconfig_set_volume_name(volume, name));
1706 }
1707
1708 /*
1709 * Validate and set the interlace attribute in the given stripe
1710 * devconfig_t.
1711 *
1712 * @param volume
1713 * the devconfig_t in which to set the interlace
1714 *
1715 * @param attr
1716 * the name of the XML attribute
1717 *
1718 * @param value
1719 * the value of the XML attribute
1720 *
1721 * @return 0 on success, non-zero otherwise.
1722 */
1723 static int
validate_set_stripe_interlace(devconfig_t * stripe,char * attr,char * value)1724 validate_set_stripe_interlace(
1725 devconfig_t *stripe,
1726 char *attr,
1727 char *value)
1728 {
1729 int error;
1730 uint64_t interlace = 0;
1731
1732 /* Convert interlace string to bytes */
1733 if ((error = sizestr_to_bytes(
1734 value, &interlace, interlace_units)) != 0) {
1735 return (error);
1736 }
1737
1738 /* Set interlace in stripe */
1739 return (devconfig_set_stripe_interlace(stripe, interlace));
1740 }
1741
1742 /*
1743 * Validate and set the mincomp attribute in the given stripe
1744 * devconfig_t.
1745 *
1746 * @param volume
1747 * the devconfig_t in which to set the mincomp
1748 *
1749 * @param attr
1750 * the name of the XML attribute
1751 *
1752 * @param value
1753 * the value of the XML attribute
1754 *
1755 * @return 0 on success, non-zero otherwise.
1756 */
1757 static int
validate_set_stripe_mincomp(devconfig_t * stripe,char * attr,char * value)1758 validate_set_stripe_mincomp(
1759 devconfig_t *stripe,
1760 char *attr,
1761 char *value)
1762 {
1763 uint16_t mincomp;
1764
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);
1771 }
1772
1773 /* Set in stripe */
1774 return (devconfig_set_stripe_mincomp(stripe, mincomp));
1775 }
1776
1777 /*
1778 * Validate and set the maxcomp attribute in the given stripe
1779 * devconfig_t.
1780 *
1781 * @param volume
1782 * the devconfig_t in which to set the maxcomp
1783 *
1784 * @param attr
1785 * the name of the XML attribute
1786 *
1787 * @param value
1788 * the value of the XML attribute
1789 *
1790 * @return 0 on success, non-zero otherwise.
1791 */
1792 static int
validate_set_stripe_maxcomp(devconfig_t * stripe,char * attr,char * value)1793 validate_set_stripe_maxcomp(
1794 devconfig_t *stripe,
1795 char *attr,
1796 char *value)
1797 {
1798 uint16_t maxcomp;
1799
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);
1806 }
1807
1808 /* Set in stripe */
1809 return (devconfig_set_stripe_maxcomp(stripe, maxcomp));
1810 }
1811
1812 /*
1813 * Validate and set the usehsp attribute in the given volume
1814 * devconfig_t.
1815 *
1816 * @param volume
1817 * the devconfig_t in which to set the usehsp
1818 *
1819 * @param attr
1820 * the name of the XML attribute
1821 *
1822 * @param value
1823 * the value of the XML attribute
1824 *
1825 * @return 0 on success, non-zero otherwise.
1826 */
1827 static int
validate_set_volume_usehsp(devconfig_t * volume,char * attr,char * value)1828 validate_set_volume_usehsp(
1829 devconfig_t *volume,
1830 char *attr,
1831 char *value)
1832 {
1833 boolean_t usehsp;
1834
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);
1841 }
1842
1843 /* Set in volume */
1844 return (devconfig_set_volume_usehsp(volume, usehsp));
1845 }
1846
1847 /*
1848 * Validate and set the nsubmirrors attribute in the given mirror
1849 * devconfig_t.
1850 *
1851 * @param volume
1852 * the devconfig_t in which to set the nsubmirrors
1853 *
1854 * @param attr
1855 * the name of the XML attribute
1856 *
1857 * @param value
1858 * the value of the XML attribute
1859 *
1860 * @return 0 on success, non-zero otherwise.
1861 */
1862 static int
validate_set_mirror_nsubmirrors(devconfig_t * mirror,char * attr,char * value)1863 validate_set_mirror_nsubmirrors(
1864 devconfig_t *mirror,
1865 char *attr,
1866 char *value)
1867 {
1868 uint16_t nsubmirrors;
1869
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);
1876 }
1877
1878 /* Set in stripe */
1879 return (devconfig_set_mirror_nsubs(mirror, nsubmirrors));
1880 }
1881
1882 /*
1883 * Validate and set the read attribute in the given mirror
1884 * devconfig_t.
1885 *
1886 * @param volume
1887 * the devconfig_t in which to set the read
1888 *
1889 * @param attr
1890 * the name of the XML attribute
1891 *
1892 * @param value
1893 * the value of the XML attribute
1894 *
1895 * @return 0 on success, non-zero otherwise.
1896 */
1897 static int
validate_set_mirror_read(devconfig_t * mirror,char * attr,char * value)1898 validate_set_mirror_read(
1899 devconfig_t *mirror,
1900 char *attr,
1901 char *value)
1902 {
1903 mirror_read_strategy_t strategy;
1904
1905 if (strcmp(value, VALID_MIRROR_READ_ROUNDROBIN) == 0) {
1906 strategy = MIRROR_READ_ROUNDROBIN;
1907 } else
1908
1909 if (strcmp(value, VALID_MIRROR_READ_GEOMETRIC) == 0) {
1910 strategy = MIRROR_READ_GEOMETRIC;
1911 } else
1912
1913 if (strcmp(value, VALID_MIRROR_READ_FIRST) == 0) {
1914 strategy = MIRROR_READ_FIRST;
1915 } else
1916
1917 {
1918 volume_set_error(gettext("%s: invalid mirror read value"), value);
1919 return (-1);
1920 }
1921
1922 return (devconfig_set_mirror_read(mirror, strategy));
1923 }
1924
1925 /*
1926 * Validate and set the write attribute in the given mirror
1927 * devconfig_t.
1928 *
1929 * @param volume
1930 * the devconfig_t in which to set the write
1931 *
1932 * @param attr
1933 * the name of the XML attribute
1934 *
1935 * @param value
1936 * the value of the XML attribute
1937 *
1938 * @return 0 on success, non-zero otherwise.
1939 */
1940 static int
validate_set_mirror_write(devconfig_t * mirror,char * attr,char * value)1941 validate_set_mirror_write(
1942 devconfig_t *mirror,
1943 char *attr,
1944 char *value)
1945 {
1946 mirror_write_strategy_t strategy;
1947
1948 if (strcmp(value, VALID_MIRROR_WRITE_PARALLEL) == 0) {
1949 strategy = MIRROR_WRITE_PARALLEL;
1950 } else
1951
1952 if (strcmp(value, VALID_MIRROR_WRITE_SERIAL) == 0) {
1953 strategy = MIRROR_WRITE_SERIAL;
1954 } else
1955
1956 {
1957 volume_set_error(gettext("%s: invalid mirror write value"), value);
1958 return (-1);
1959 }
1960
1961 return (devconfig_set_mirror_write(mirror, strategy));
1962 }
1963
1964 /*
1965 * Validate and set the passnum attribute in the given mirror
1966 * devconfig_t.
1967 *
1968 * @param volume
1969 * the devconfig_t in which to set the passnum
1970 *
1971 * @param attr
1972 * the name of the XML attribute
1973 *
1974 * @param value
1975 * the value of the XML attribute
1976 *
1977 * @return 0 on success, non-zero otherwise.
1978 */
1979 static int
validate_set_mirror_passnum(devconfig_t * mirror,char * attr,char * value)1980 validate_set_mirror_passnum(
1981 devconfig_t *mirror,
1982 char *attr,
1983 char *value)
1984 {
1985 uint16_t passnum;
1986
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);
1993 }
1994
1995 /* Set in stripe */
1996 return (devconfig_set_mirror_pass(mirror, passnum));
1997 }
1998
1999 /*
2000 * Validate and set the redundancy attribute in the given volume
2001 * devconfig_t.
2002 *
2003 * @param volume
2004 * the devconfig_t in which to set the redundancy
2005 *
2006 * @param attr
2007 * the name of the XML attribute
2008 *
2009 * @param value
2010 * the value of the XML attribute
2011 *
2012 * @return 0 on success, non-zero otherwise.
2013 */
2014 static int
validate_set_volume_redundancy(devconfig_t * volume,char * attr,char * value)2015 validate_set_volume_redundancy(
2016 devconfig_t *volume,
2017 char *attr,
2018 char *value)
2019 {
2020 uint16_t redundancy;
2021
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);
2028 }
2029
2030 /* Set in stripe */
2031 return (devconfig_set_volume_redundancy_level(volume, redundancy));
2032 }
2033
2034 /*
2035 * Validate and set the datapaths attribute in the given volume
2036 * devconfig_t.
2037 *
2038 * @param volume
2039 * the devconfig_t in which to set the datapaths
2040 *
2041 * @param attr
2042 * the name of the XML attribute
2043 *
2044 * @param value
2045 * the value of the XML attribute
2046 *
2047 * @return 0 on success, non-zero otherwise.
2048 */
2049 static int
validate_set_volume_datapaths(devconfig_t * volume,char * attr,char * value)2050 validate_set_volume_datapaths(
2051 devconfig_t *volume,
2052 char *attr,
2053 char *value)
2054 {
2055 uint16_t redundancy;
2056
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);
2063 }
2064
2065 /* Set in stripe */
2066 return (devconfig_set_volume_npaths(volume, redundancy));
2067 }
2068
2069 /*
2070 * ******************************************************************
2071 *
2072 * XML attribute accessors/converters
2073 *
2074 * These functions get a value from the appropriate devconfig_t
2075 * accessor, and then convert it to a string.
2076 *
2077 * ******************************************************************
2078 */
2079
2080 /*
2081 * Get, as a string, the value of the name attribute of the given
2082 * devconfig_t. This data must be freed.
2083 *
2084 * @param device
2085 * the devconfig_t from which to retrieve the name
2086 *
2087 * @param attr
2088 * the name of the XML attribute
2089 *
2090 * @param value
2091 * RETURN: the value of the XML attribute
2092 *
2093 * @return 0 on success, non-zero otherwise.
2094 */
2095 static int
get_as_string_name(devconfig_t * device,char * attr,char ** value)2096 get_as_string_name(
2097 devconfig_t *device,
2098 char *attr,
2099 char **value)
2100 {
2101 int error;
2102 char *name;
2103
2104 /* Get name */
2105 if ((error = devconfig_get_name(device, &name)) == 0) {
2106 if ((*value = strdup(name)) == NULL) {
2107 error = ENOMEM;
2108 }
2109 }
2110
2111 return (error);
2112 }
2113
2114 /*
2115 * Get, as a string, the value of the passnum attribute of the given
2116 * mirror devconfig_t. This data must be freed.
2117 *
2118 * @param device
2119 * the devconfig_t from which to retrieve the passnum
2120 *
2121 * @param attr
2122 * the name of the XML attribute
2123 *
2124 * @param value
2125 * RETURN: the value of the XML attribute
2126 *
2127 * @return 0 on success, non-zero otherwise.
2128 */
2129 static int
get_as_string_mirror_passnum(devconfig_t * mirror,char * attr,char ** value)2130 get_as_string_mirror_passnum(
2131 devconfig_t *mirror,
2132 char *attr,
2133 char **value)
2134 {
2135 int error;
2136 uint16_t passnum;
2137
2138 /* Get mirror pass number */
2139 if ((error = devconfig_get_mirror_pass(mirror, &passnum)) == 0) {
2140 error = ll_to_str(passnum, value);
2141 }
2142
2143 return (error);
2144 }
2145
2146 /*
2147 * Get, as a string, the value of the read attribute of the given
2148 * mirror devconfig_t. This data must be freed.
2149 *
2150 * @param device
2151 * the devconfig_t from which to retrieve the read
2152 *
2153 * @param attr
2154 * the name of the XML attribute
2155 *
2156 * @param value
2157 * RETURN: the value of the XML attribute
2158 *
2159 * @return 0 on success, non-zero otherwise.
2160 */
2161 static int
get_as_string_mirror_read(devconfig_t * mirror,char * attr,char ** value)2162 get_as_string_mirror_read(
2163 devconfig_t *mirror,
2164 char *attr,
2165 char **value)
2166 {
2167 int error;
2168 mirror_read_strategy_t read;
2169
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;
2175 }
2176 }
2177
2178 return (error);
2179 }
2180
2181 /*
2182 * Get, as a string, the value of the write attribute of the given
2183 * mirror devconfig_t. This data must be freed.
2184 *
2185 * @param device
2186 * the devconfig_t from which to retrieve the write
2187 *
2188 * @param attr
2189 * the name of the XML attribute
2190 *
2191 * @param value
2192 * RETURN: the value of the XML attribute
2193 *
2194 * @return 0 on success, non-zero otherwise.
2195 */
2196 static int
get_as_string_mirror_write(devconfig_t * mirror,char * attr,char ** value)2197 get_as_string_mirror_write(
2198 devconfig_t *mirror,
2199 char *attr,
2200 char **value)
2201 {
2202 int error;
2203 mirror_write_strategy_t write;
2204
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;
2210 }
2211 }
2212
2213 return (error);
2214 }
2215
2216 /*
2217 * Get, as a string, the value of the in_blocks attribute of the given
2218 * device devconfig_t. This data must be freed.
2219 *
2220 * @param device
2221 * the devconfig_t from which to retrieve the in_blocks
2222 *
2223 * @param attr
2224 * the name of the XML attribute
2225 *
2226 * @param value
2227 * RETURN: the value of the XML attribute
2228 *
2229 * @return 0 on success, non-zero otherwise.
2230 */
2231 static int
get_as_string_size_in_blocks(devconfig_t * device,char * attr,char ** value)2232 get_as_string_size_in_blocks(
2233 devconfig_t *device,
2234 char *attr,
2235 char **value)
2236 {
2237 int error;
2238 uint64_t size;
2239
2240 /* Get size in blocks */
2241 if ((error = devconfig_get_size_in_blocks(device, &size)) == 0) {
2242 error = ll_to_str(size, value);
2243 }
2244
2245 return (error);
2246 }
2247
2248 /*
2249 * Get, as a string, the value of the start_block attribute of the
2250 * given slice devconfig_t. This data must be freed.
2251 *
2252 * @param device
2253 * the devconfig_t from which to retrieve the start_block
2254 *
2255 * @param attr
2256 * the name of the XML attribute
2257 *
2258 * @param value
2259 * RETURN: the value of the XML attribute
2260 *
2261 * @return 0 on success, non-zero otherwise.
2262 */
2263 static int
get_as_string_slice_start_block(devconfig_t * slice,char * attr,char ** value)2264 get_as_string_slice_start_block(
2265 devconfig_t *slice,
2266 char *attr,
2267 char **value)
2268 {
2269 int error;
2270 uint64_t start;
2271
2272 /* Get slice start block */
2273 if ((error = devconfig_get_slice_start_block(slice, &start)) == 0) {
2274 error = ll_to_str(start, value);
2275 }
2276
2277 return (error);
2278 }
2279
2280 /*
2281 * Get, as a string, the value of the interlace attribute of the given
2282 * stripe devconfig_t. This data must be freed.
2283 *
2284 * @param device
2285 * the devconfig_t from which to retrieve the interlace
2286 *
2287 * @param attr
2288 * the name of the XML attribute
2289 *
2290 * @param value
2291 * RETURN: the value of the XML attribute
2292 *
2293 * @return 0 on success, non-zero otherwise.
2294 */
2295 static int
get_as_string_stripe_interlace(devconfig_t * stripe,char * attr,char ** value)2296 get_as_string_stripe_interlace(
2297 devconfig_t *stripe,
2298 char *attr,
2299 char **value)
2300 {
2301 int error;
2302 uint64_t interlace;
2303
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);
2308 }
2309
2310 return (error);
2311 }
2312