1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate * CDDL HEADER START
3*0Sstevel@tonic-gate *
4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance
7*0Sstevel@tonic-gate * with the License.
8*0Sstevel@tonic-gate *
9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate * and limitations under the License.
13*0Sstevel@tonic-gate *
14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate *
20*0Sstevel@tonic-gate * CDDL HEADER END
21*0Sstevel@tonic-gate */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24*0Sstevel@tonic-gate * Use is subject to license terms.
25*0Sstevel@tonic-gate */
26*0Sstevel@tonic-gate
27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
28*0Sstevel@tonic-gate
29*0Sstevel@tonic-gate /*
30*0Sstevel@tonic-gate * Front end CLI to metassist. Parses command line, reads in data
31*0Sstevel@tonic-gate * files, provides main() entry point into metassist. Here's the
32*0Sstevel@tonic-gate * complete data validation stack for the project:
33*0Sstevel@tonic-gate *
34*0Sstevel@tonic-gate * 1. Controller validates command line syntax/order of arguments.
35*0Sstevel@tonic-gate *
36*0Sstevel@tonic-gate * 2. XML parser validates XML syntax, conformance with DTD
37*0Sstevel@tonic-gate *
38*0Sstevel@tonic-gate * 3. xml_convert validates proper conversion from string to
39*0Sstevel@tonic-gate * size/integer/float/boolean/etc.
40*0Sstevel@tonic-gate *
41*0Sstevel@tonic-gate * 4. devconfig_t mutators validate limits/boundaries/min/max/names of
42*0Sstevel@tonic-gate * data. References md_mdiox.h and possibly libmeta.
43*0Sstevel@tonic-gate *
44*0Sstevel@tonic-gate * 5. layout validates on remaining issues, including existence of
45*0Sstevel@tonic-gate * given devices, feasibility of request, suitability of specified
46*0Sstevel@tonic-gate * components, and subtle misuse of data structure (like both size
47*0Sstevel@tonic-gate * and components specified).
48*0Sstevel@tonic-gate */
49*0Sstevel@tonic-gate
50*0Sstevel@tonic-gate #include "metassist.h"
51*0Sstevel@tonic-gate
52*0Sstevel@tonic-gate #include <errno.h>
53*0Sstevel@tonic-gate #include <libintl.h>
54*0Sstevel@tonic-gate
55*0Sstevel@tonic-gate #include <math.h>
56*0Sstevel@tonic-gate #include <signal.h>
57*0Sstevel@tonic-gate #include <string.h>
58*0Sstevel@tonic-gate #include <sys/stat.h>
59*0Sstevel@tonic-gate #include <sys/utsname.h>
60*0Sstevel@tonic-gate #include <sys/wait.h>
61*0Sstevel@tonic-gate #include <unistd.h>
62*0Sstevel@tonic-gate #include "getopt_ext.h"
63*0Sstevel@tonic-gate #include "locale.h"
64*0Sstevel@tonic-gate #include "volume_error.h"
65*0Sstevel@tonic-gate #include "volume_output.h"
66*0Sstevel@tonic-gate #include "volume_request.h"
67*0Sstevel@tonic-gate #include "volume_defaults.h"
68*0Sstevel@tonic-gate #include "volume_string.h"
69*0Sstevel@tonic-gate #include "xml_convert.h"
70*0Sstevel@tonic-gate #include "layout.h"
71*0Sstevel@tonic-gate
72*0Sstevel@tonic-gate /*
73*0Sstevel@tonic-gate * Function prototypes
74*0Sstevel@tonic-gate */
75*0Sstevel@tonic-gate
76*0Sstevel@tonic-gate static void clean_up();
77*0Sstevel@tonic-gate static void interrupthandler(int x);
78*0Sstevel@tonic-gate static int copy_arg(char *option, char *value, char **saveto);
79*0Sstevel@tonic-gate static xmlDocPtr create_volume_request_XML();
80*0Sstevel@tonic-gate static int handle_common_opts(int c, boolean_t *handled);
81*0Sstevel@tonic-gate static int parse_create_opts(int argc, char *argv[]);
82*0Sstevel@tonic-gate static int parse_opts(int argc, char *argv[]);
83*0Sstevel@tonic-gate static int parse_tokenized_list(const char *string, dlist_t **list);
84*0Sstevel@tonic-gate static int parse_verbose_arg(char *arg, int *verbosity);
85*0Sstevel@tonic-gate static void print_help_create(FILE *stream);
86*0Sstevel@tonic-gate static void print_help_main(FILE *stream);
87*0Sstevel@tonic-gate static void print_manual_reference(FILE *stream);
88*0Sstevel@tonic-gate static void print_usage(FILE *stream);
89*0Sstevel@tonic-gate static void print_usage_create(FILE *stream);
90*0Sstevel@tonic-gate static void print_usage_main(FILE *stream);
91*0Sstevel@tonic-gate static int print_version(FILE *stream);
92*0Sstevel@tonic-gate static int get_doc_from_file(
93*0Sstevel@tonic-gate char *file, char **valid_types, xmlDocPtr *doc, char **root);
94*0Sstevel@tonic-gate static int get_volume_request_or_config(xmlDocPtr *doc, char **root);
95*0Sstevel@tonic-gate static int handle_commands(char *commands);
96*0Sstevel@tonic-gate static int handle_config(devconfig_t *config);
97*0Sstevel@tonic-gate static int handle_request(request_t *request, defaults_t *defaults);
98*0Sstevel@tonic-gate static int write_temp_file(char *text, mode_t mode, char **file);
99*0Sstevel@tonic-gate
100*0Sstevel@tonic-gate /*
101*0Sstevel@tonic-gate * Data
102*0Sstevel@tonic-gate */
103*0Sstevel@tonic-gate
104*0Sstevel@tonic-gate /* Holds argv[0] */
105*0Sstevel@tonic-gate char *progname;
106*0Sstevel@tonic-gate
107*0Sstevel@tonic-gate /* The action to take */
108*0Sstevel@tonic-gate int action = ACTION_EXECUTE;
109*0Sstevel@tonic-gate
110*0Sstevel@tonic-gate /* Holds the name of the temporary command file */
111*0Sstevel@tonic-gate char *commandfile = NULL;
112*0Sstevel@tonic-gate
113*0Sstevel@tonic-gate /* The metassist subcommand */
114*0Sstevel@tonic-gate int subcmd = SUBCMD_NONE;
115*0Sstevel@tonic-gate
116*0Sstevel@tonic-gate /* The volume-request XML file to read */
117*0Sstevel@tonic-gate char *arg_inputfile = NULL;
118*0Sstevel@tonic-gate
119*0Sstevel@tonic-gate /* The size of the requested volume */
120*0Sstevel@tonic-gate char *arg_size = NULL;
121*0Sstevel@tonic-gate
122*0Sstevel@tonic-gate /* The disk set to use */
123*0Sstevel@tonic-gate char *arg_diskset = NULL;
124*0Sstevel@tonic-gate
125*0Sstevel@tonic-gate /* The volume name to use */
126*0Sstevel@tonic-gate char *arg_name = NULL;
127*0Sstevel@tonic-gate
128*0Sstevel@tonic-gate /* Redundancy level */
129*0Sstevel@tonic-gate char *arg_redundancy = NULL;
130*0Sstevel@tonic-gate
131*0Sstevel@tonic-gate /* Number of datapaths */
132*0Sstevel@tonic-gate char *arg_datapaths = NULL;
133*0Sstevel@tonic-gate
134*0Sstevel@tonic-gate /* Whether to implement fault recovery */
135*0Sstevel@tonic-gate boolean_t faultrecovery = B_FALSE;
136*0Sstevel@tonic-gate
137*0Sstevel@tonic-gate /* Whether to output the config file */
138*0Sstevel@tonic-gate boolean_t output_configfile = B_FALSE;
139*0Sstevel@tonic-gate
140*0Sstevel@tonic-gate /* Whether to output the command file instead of */
141*0Sstevel@tonic-gate boolean_t output_commandfile = B_FALSE;
142*0Sstevel@tonic-gate
143*0Sstevel@tonic-gate /* List of available devices */
144*0Sstevel@tonic-gate dlist_t *available = NULL;
145*0Sstevel@tonic-gate
146*0Sstevel@tonic-gate /* List of unavailable devices */
147*0Sstevel@tonic-gate dlist_t *unavailable = NULL;
148*0Sstevel@tonic-gate
149*0Sstevel@tonic-gate /*
150*0Sstevel@tonic-gate * Functions
151*0Sstevel@tonic-gate */
152*0Sstevel@tonic-gate
153*0Sstevel@tonic-gate /*
154*0Sstevel@tonic-gate * Frees alloc'd memory, to be called prior to exiting.
155*0Sstevel@tonic-gate */
156*0Sstevel@tonic-gate static void
clean_up()157*0Sstevel@tonic-gate clean_up()
158*0Sstevel@tonic-gate {
159*0Sstevel@tonic-gate /* Remove temporary command file */
160*0Sstevel@tonic-gate if (commandfile != NULL) {
161*0Sstevel@tonic-gate /* Ignore failure */
162*0Sstevel@tonic-gate unlink(commandfile);
163*0Sstevel@tonic-gate }
164*0Sstevel@tonic-gate
165*0Sstevel@tonic-gate /* Free allocated argument strings */
166*0Sstevel@tonic-gate if (commandfile != NULL) free(commandfile);
167*0Sstevel@tonic-gate if (arg_diskset != NULL) free(arg_diskset);
168*0Sstevel@tonic-gate if (arg_name != NULL) free(arg_name);
169*0Sstevel@tonic-gate if (arg_inputfile != NULL) free(arg_inputfile);
170*0Sstevel@tonic-gate
171*0Sstevel@tonic-gate /* Free available dlist and strings within */
172*0Sstevel@tonic-gate dlist_free_items(available, free);
173*0Sstevel@tonic-gate
174*0Sstevel@tonic-gate /* Free unavailable dlist and strings within */
175*0Sstevel@tonic-gate dlist_free_items(unavailable, free);
176*0Sstevel@tonic-gate
177*0Sstevel@tonic-gate /* Clean up XML data structures */
178*0Sstevel@tonic-gate cleanup_xml();
179*0Sstevel@tonic-gate }
180*0Sstevel@tonic-gate
181*0Sstevel@tonic-gate /*
182*0Sstevel@tonic-gate * Signal handler, called to exit gracefully
183*0Sstevel@tonic-gate */
184*0Sstevel@tonic-gate static void
interrupthandler(int sig)185*0Sstevel@tonic-gate interrupthandler(
186*0Sstevel@tonic-gate int sig)
187*0Sstevel@tonic-gate {
188*0Sstevel@tonic-gate char sigstr[SIG2STR_MAX];
189*0Sstevel@tonic-gate
190*0Sstevel@tonic-gate if (sig2str(sig, sigstr) != 0) {
191*0Sstevel@tonic-gate sigstr[0] = '\0';
192*0Sstevel@tonic-gate }
193*0Sstevel@tonic-gate
194*0Sstevel@tonic-gate fprintf(stderr,
195*0Sstevel@tonic-gate gettext("Signal %d (%s) caught -- exiting...\n"), sig, sigstr);
196*0Sstevel@tonic-gate
197*0Sstevel@tonic-gate /* Allow layout to cleanup on abnormal exit */
198*0Sstevel@tonic-gate layout_clean_up();
199*0Sstevel@tonic-gate
200*0Sstevel@tonic-gate clean_up();
201*0Sstevel@tonic-gate exit(1);
202*0Sstevel@tonic-gate }
203*0Sstevel@tonic-gate
204*0Sstevel@tonic-gate /*
205*0Sstevel@tonic-gate * Copies and saves the given argument, verifying that the argument
206*0Sstevel@tonic-gate * has not already been saved.
207*0Sstevel@tonic-gate *
208*0Sstevel@tonic-gate * @param option
209*0Sstevel@tonic-gate * The flag preceding or type of the argument. Used only
210*0Sstevel@tonic-gate * in the error message when an option has already been
211*0Sstevel@tonic-gate * saved to *saveto.
212*0Sstevel@tonic-gate *
213*0Sstevel@tonic-gate * @param value
214*0Sstevel@tonic-gate * The argument to be copied.
215*0Sstevel@tonic-gate *
216*0Sstevel@tonic-gate * @param saveto
217*0Sstevel@tonic-gate * Changed to point to the copied data. This must point
218*0Sstevel@tonic-gate * to NULL data initially, or it will be assumed that
219*0Sstevel@tonic-gate * this argument has already been set. This memory must
220*0Sstevel@tonic-gate * be free()d by the caller.
221*0Sstevel@tonic-gate *
222*0Sstevel@tonic-gate * @return 0 on success, non-zero otherwise.
223*0Sstevel@tonic-gate */
224*0Sstevel@tonic-gate static int
copy_arg(char * option,char * value,char ** saveto)225*0Sstevel@tonic-gate copy_arg(
226*0Sstevel@tonic-gate char *option,
227*0Sstevel@tonic-gate char *value,
228*0Sstevel@tonic-gate char **saveto)
229*0Sstevel@tonic-gate {
230*0Sstevel@tonic-gate int error = 0;
231*0Sstevel@tonic-gate
232*0Sstevel@tonic-gate /* Has this string already been set? */
233*0Sstevel@tonic-gate if (*saveto != NULL) {
234*0Sstevel@tonic-gate volume_set_error(
235*0Sstevel@tonic-gate gettext("%s: option specified multiple times"), option);
236*0Sstevel@tonic-gate error = -1;
237*0Sstevel@tonic-gate } else
238*0Sstevel@tonic-gate
239*0Sstevel@tonic-gate if ((*saveto = strdup(value)) == NULL) {
240*0Sstevel@tonic-gate error = ENOMEM;
241*0Sstevel@tonic-gate }
242*0Sstevel@tonic-gate
243*0Sstevel@tonic-gate return (error);
244*0Sstevel@tonic-gate }
245*0Sstevel@tonic-gate
246*0Sstevel@tonic-gate /*
247*0Sstevel@tonic-gate * Generates the XML volume request corresponding to the command-line
248*0Sstevel@tonic-gate * parameters. No DTD node is included in this request.
249*0Sstevel@tonic-gate *
250*0Sstevel@tonic-gate * @return The XML request, or NULL if an error ocurred in
251*0Sstevel@tonic-gate * generating the text. This memory must be freed with
252*0Sstevel@tonic-gate * XMLFree().
253*0Sstevel@tonic-gate */
254*0Sstevel@tonic-gate static xmlDocPtr
create_volume_request_XML()255*0Sstevel@tonic-gate create_volume_request_XML()
256*0Sstevel@tonic-gate {
257*0Sstevel@tonic-gate xmlDocPtr doc;
258*0Sstevel@tonic-gate xmlNodePtr request, volume;
259*0Sstevel@tonic-gate
260*0Sstevel@tonic-gate /* Create the XML document */
261*0Sstevel@tonic-gate doc = xmlNewDoc((xmlChar *)"1.0");
262*0Sstevel@tonic-gate
263*0Sstevel@tonic-gate /* Create the root node */
264*0Sstevel@tonic-gate request = xmlNewDocNode(
265*0Sstevel@tonic-gate doc, NULL, (xmlChar *)ELEMENT_VOLUMEREQUEST, NULL);
266*0Sstevel@tonic-gate xmlAddChild((xmlNodePtr) doc, (xmlNodePtr)request);
267*0Sstevel@tonic-gate
268*0Sstevel@tonic-gate /* diskset element */
269*0Sstevel@tonic-gate if (arg_diskset != NULL) {
270*0Sstevel@tonic-gate xmlNodePtr node = xmlNewChild(
271*0Sstevel@tonic-gate request, NULL, (xmlChar *)ELEMENT_DISKSET, NULL);
272*0Sstevel@tonic-gate xmlSetProp(node,
273*0Sstevel@tonic-gate (xmlChar *)ATTR_NAME, (xmlChar *)arg_diskset);
274*0Sstevel@tonic-gate }
275*0Sstevel@tonic-gate
276*0Sstevel@tonic-gate /* available elements */
277*0Sstevel@tonic-gate if (available != NULL) {
278*0Sstevel@tonic-gate dlist_t *item;
279*0Sstevel@tonic-gate for (item = available; item != NULL; item = item->next) {
280*0Sstevel@tonic-gate xmlNodePtr node = xmlNewChild(
281*0Sstevel@tonic-gate request, NULL, (xmlChar *)ELEMENT_AVAILABLE, NULL);
282*0Sstevel@tonic-gate xmlSetProp(node,
283*0Sstevel@tonic-gate (xmlChar *)ATTR_NAME, (xmlChar *)item->obj);
284*0Sstevel@tonic-gate }
285*0Sstevel@tonic-gate }
286*0Sstevel@tonic-gate
287*0Sstevel@tonic-gate /* unavailable elements */
288*0Sstevel@tonic-gate if (unavailable != NULL) {
289*0Sstevel@tonic-gate dlist_t *item;
290*0Sstevel@tonic-gate for (item = unavailable; item != NULL; item = item->next) {
291*0Sstevel@tonic-gate xmlNodePtr node = xmlNewChild(
292*0Sstevel@tonic-gate request, NULL, (xmlChar *)ELEMENT_UNAVAILABLE, NULL);
293*0Sstevel@tonic-gate xmlSetProp(node,
294*0Sstevel@tonic-gate (xmlChar *)ATTR_NAME, (xmlChar *)item->obj);
295*0Sstevel@tonic-gate }
296*0Sstevel@tonic-gate }
297*0Sstevel@tonic-gate
298*0Sstevel@tonic-gate /* volume element */
299*0Sstevel@tonic-gate volume = xmlNewChild(request, NULL, (xmlChar *)ELEMENT_VOLUME, NULL);
300*0Sstevel@tonic-gate
301*0Sstevel@tonic-gate /* Volume name - optional */
302*0Sstevel@tonic-gate if (arg_name != NULL) {
303*0Sstevel@tonic-gate xmlSetProp(volume,
304*0Sstevel@tonic-gate (xmlChar *)ATTR_NAME, (xmlChar *)arg_name);
305*0Sstevel@tonic-gate }
306*0Sstevel@tonic-gate
307*0Sstevel@tonic-gate /* Volume size - required */
308*0Sstevel@tonic-gate xmlSetProp(volume, (xmlChar *)ATTR_SIZEINBYTES, (xmlChar *)arg_size);
309*0Sstevel@tonic-gate
310*0Sstevel@tonic-gate /* Volume redundancy - optional */
311*0Sstevel@tonic-gate if (arg_redundancy != NULL) {
312*0Sstevel@tonic-gate xmlSetProp(volume,
313*0Sstevel@tonic-gate (xmlChar *)ATTR_VOLUME_REDUNDANCY, (xmlChar *)arg_redundancy);
314*0Sstevel@tonic-gate }
315*0Sstevel@tonic-gate
316*0Sstevel@tonic-gate /* Volume fault recovery - optional */
317*0Sstevel@tonic-gate if (faultrecovery == B_TRUE) {
318*0Sstevel@tonic-gate xmlSetProp(volume,
319*0Sstevel@tonic-gate (xmlChar *)ATTR_VOLUME_FAULTRECOVERY, (xmlChar *)"TRUE");
320*0Sstevel@tonic-gate }
321*0Sstevel@tonic-gate
322*0Sstevel@tonic-gate /* Volume datapaths - optional */
323*0Sstevel@tonic-gate if (arg_datapaths != NULL) {
324*0Sstevel@tonic-gate xmlSetProp(volume,
325*0Sstevel@tonic-gate (xmlChar *)ATTR_VOLUME_DATAPATHS, (xmlChar *)arg_datapaths);
326*0Sstevel@tonic-gate }
327*0Sstevel@tonic-gate
328*0Sstevel@tonic-gate if (get_max_verbosity() >= OUTPUT_DEBUG) {
329*0Sstevel@tonic-gate xmlChar *text;
330*0Sstevel@tonic-gate /* Get the text dump */
331*0Sstevel@tonic-gate xmlDocDumpFormatMemory(doc, &text, NULL, 1);
332*0Sstevel@tonic-gate oprintf(OUTPUT_DEBUG,
333*0Sstevel@tonic-gate gettext("Generated volume-request:\n%s"), text);
334*0Sstevel@tonic-gate xmlFree(text);
335*0Sstevel@tonic-gate }
336*0Sstevel@tonic-gate
337*0Sstevel@tonic-gate return (doc);
338*0Sstevel@tonic-gate }
339*0Sstevel@tonic-gate
340*0Sstevel@tonic-gate /*
341*0Sstevel@tonic-gate * Checks the given flag for options common to all subcommands.
342*0Sstevel@tonic-gate *
343*0Sstevel@tonic-gate * @param c
344*0Sstevel@tonic-gate * The option letter.
345*0Sstevel@tonic-gate *
346*0Sstevel@tonic-gate * @param handled
347*0Sstevel@tonic-gate * RETURN: whether the given option flag was handled.
348*0Sstevel@tonic-gate *
349*0Sstevel@tonic-gate * @return Non-zero if an error occurred or the given option was
350*0Sstevel@tonic-gate * invalid or incomplete, 0 otherwise.
351*0Sstevel@tonic-gate */
352*0Sstevel@tonic-gate static int
handle_common_opts(int c,boolean_t * handled)353*0Sstevel@tonic-gate handle_common_opts(
354*0Sstevel@tonic-gate int c,
355*0Sstevel@tonic-gate boolean_t *handled)
356*0Sstevel@tonic-gate {
357*0Sstevel@tonic-gate int error = 0;
358*0Sstevel@tonic-gate
359*0Sstevel@tonic-gate /* Level of verbosity to report */
360*0Sstevel@tonic-gate int verbosity;
361*0Sstevel@tonic-gate
362*0Sstevel@tonic-gate *handled = B_TRUE;
363*0Sstevel@tonic-gate
364*0Sstevel@tonic-gate switch (c) {
365*0Sstevel@tonic-gate case COMMON_SHORTOPT_VERBOSITY:
366*0Sstevel@tonic-gate if ((error = parse_verbose_arg(optarg, &verbosity)) == 0) {
367*0Sstevel@tonic-gate set_max_verbosity(verbosity, stderr);
368*0Sstevel@tonic-gate }
369*0Sstevel@tonic-gate break;
370*0Sstevel@tonic-gate
371*0Sstevel@tonic-gate case COMMON_SHORTOPT_VERSION:
372*0Sstevel@tonic-gate if ((error = print_version(stdout)) == 0) {
373*0Sstevel@tonic-gate clean_up();
374*0Sstevel@tonic-gate exit(0);
375*0Sstevel@tonic-gate }
376*0Sstevel@tonic-gate break;
377*0Sstevel@tonic-gate
378*0Sstevel@tonic-gate case GETOPT_ERR_MISSING_ARG:
379*0Sstevel@tonic-gate volume_set_error(
380*0Sstevel@tonic-gate gettext("option missing a required argument: -%c"), optopt);
381*0Sstevel@tonic-gate error = -1;
382*0Sstevel@tonic-gate break;
383*0Sstevel@tonic-gate
384*0Sstevel@tonic-gate case GETOPT_ERR_INVALID_OPT:
385*0Sstevel@tonic-gate volume_set_error(gettext("invalid option: -%c"), optopt);
386*0Sstevel@tonic-gate error = -1;
387*0Sstevel@tonic-gate break;
388*0Sstevel@tonic-gate
389*0Sstevel@tonic-gate case GETOPT_ERR_INVALID_ARG:
390*0Sstevel@tonic-gate volume_set_error(gettext("invalid argument: %s"), optarg);
391*0Sstevel@tonic-gate error = -1;
392*0Sstevel@tonic-gate break;
393*0Sstevel@tonic-gate
394*0Sstevel@tonic-gate default:
395*0Sstevel@tonic-gate *handled = B_FALSE;
396*0Sstevel@tonic-gate }
397*0Sstevel@tonic-gate
398*0Sstevel@tonic-gate return (error);
399*0Sstevel@tonic-gate }
400*0Sstevel@tonic-gate
401*0Sstevel@tonic-gate /*
402*0Sstevel@tonic-gate * Parse the command line options for the create subcommand.
403*0Sstevel@tonic-gate *
404*0Sstevel@tonic-gate * @param argc
405*0Sstevel@tonic-gate * The number of arguments in the array
406*0Sstevel@tonic-gate *
407*0Sstevel@tonic-gate * @param argv
408*0Sstevel@tonic-gate * The argument array
409*0Sstevel@tonic-gate */
410*0Sstevel@tonic-gate static int
parse_create_opts(int argc,char * argv[])411*0Sstevel@tonic-gate parse_create_opts(
412*0Sstevel@tonic-gate int argc,
413*0Sstevel@tonic-gate char *argv[])
414*0Sstevel@tonic-gate {
415*0Sstevel@tonic-gate int c;
416*0Sstevel@tonic-gate int error = 0;
417*0Sstevel@tonic-gate
418*0Sstevel@tonic-gate /*
419*0Sstevel@tonic-gate * Whether a volume request is specified on the command line
420*0Sstevel@tonic-gate * (vs. a inputfile)
421*0Sstevel@tonic-gate */
422*0Sstevel@tonic-gate boolean_t request_on_command_line = B_FALSE;
423*0Sstevel@tonic-gate
424*0Sstevel@tonic-gate /* Examine next arg */
425*0Sstevel@tonic-gate while (!error && (c = getopt_ext(
426*0Sstevel@tonic-gate argc, argv, CREATE_SHORTOPTS)) != GETOPT_DONE_PARSING) {
427*0Sstevel@tonic-gate
428*0Sstevel@tonic-gate boolean_t handled;
429*0Sstevel@tonic-gate
430*0Sstevel@tonic-gate /* Check for args common to all scopes */
431*0Sstevel@tonic-gate error = handle_common_opts(c, &handled);
432*0Sstevel@tonic-gate if (error == 0 && handled == B_FALSE) {
433*0Sstevel@tonic-gate
434*0Sstevel@tonic-gate /* Check for args specific to this scope */
435*0Sstevel@tonic-gate switch (c) {
436*0Sstevel@tonic-gate
437*0Sstevel@tonic-gate /* Help */
438*0Sstevel@tonic-gate case COMMON_SHORTOPT_HELP:
439*0Sstevel@tonic-gate print_help_create(stdout);
440*0Sstevel@tonic-gate clean_up();
441*0Sstevel@tonic-gate exit(0);
442*0Sstevel@tonic-gate break;
443*0Sstevel@tonic-gate
444*0Sstevel@tonic-gate /* Config file */
445*0Sstevel@tonic-gate case CREATE_SHORTOPT_CONFIGFILE:
446*0Sstevel@tonic-gate action &= ~ACTION_EXECUTE;
447*0Sstevel@tonic-gate action |= ACTION_OUTPUT_CONFIG;
448*0Sstevel@tonic-gate break;
449*0Sstevel@tonic-gate
450*0Sstevel@tonic-gate /* Command file */
451*0Sstevel@tonic-gate case CREATE_SHORTOPT_COMMANDFILE:
452*0Sstevel@tonic-gate action &= ~ACTION_EXECUTE;
453*0Sstevel@tonic-gate action |= ACTION_OUTPUT_COMMANDS;
454*0Sstevel@tonic-gate break;
455*0Sstevel@tonic-gate
456*0Sstevel@tonic-gate /* Disk set */
457*0Sstevel@tonic-gate case CREATE_SHORTOPT_DISKSET:
458*0Sstevel@tonic-gate error = copy_arg(
459*0Sstevel@tonic-gate argv[optind - 2], optarg, &arg_diskset);
460*0Sstevel@tonic-gate request_on_command_line = B_TRUE;
461*0Sstevel@tonic-gate break;
462*0Sstevel@tonic-gate
463*0Sstevel@tonic-gate /* Name */
464*0Sstevel@tonic-gate case CREATE_SHORTOPT_NAME:
465*0Sstevel@tonic-gate error = copy_arg(
466*0Sstevel@tonic-gate argv[optind - 2], optarg, &arg_name);
467*0Sstevel@tonic-gate request_on_command_line = B_TRUE;
468*0Sstevel@tonic-gate break;
469*0Sstevel@tonic-gate
470*0Sstevel@tonic-gate /* Redundancy */
471*0Sstevel@tonic-gate case CREATE_SHORTOPT_REDUNDANCY:
472*0Sstevel@tonic-gate error = copy_arg(
473*0Sstevel@tonic-gate argv[optind - 2], optarg, &arg_redundancy);
474*0Sstevel@tonic-gate request_on_command_line = B_TRUE;
475*0Sstevel@tonic-gate break;
476*0Sstevel@tonic-gate
477*0Sstevel@tonic-gate /* Data paths */
478*0Sstevel@tonic-gate case CREATE_SHORTOPT_DATAPATHS:
479*0Sstevel@tonic-gate error = copy_arg(
480*0Sstevel@tonic-gate argv[optind - 2], optarg, &arg_datapaths);
481*0Sstevel@tonic-gate request_on_command_line = B_TRUE;
482*0Sstevel@tonic-gate break;
483*0Sstevel@tonic-gate
484*0Sstevel@tonic-gate /* Fault recovery */
485*0Sstevel@tonic-gate case CREATE_SHORTOPT_FAULTRECOVERY:
486*0Sstevel@tonic-gate faultrecovery = B_TRUE;
487*0Sstevel@tonic-gate request_on_command_line = B_TRUE;
488*0Sstevel@tonic-gate break;
489*0Sstevel@tonic-gate
490*0Sstevel@tonic-gate /* Available devices */
491*0Sstevel@tonic-gate case CREATE_SHORTOPT_AVAILABLE:
492*0Sstevel@tonic-gate error = parse_tokenized_list(optarg, &available);
493*0Sstevel@tonic-gate request_on_command_line = B_TRUE;
494*0Sstevel@tonic-gate break;
495*0Sstevel@tonic-gate
496*0Sstevel@tonic-gate /* Unavailable devices */
497*0Sstevel@tonic-gate case CREATE_SHORTOPT_UNAVAILABLE:
498*0Sstevel@tonic-gate error = parse_tokenized_list(optarg, &unavailable);
499*0Sstevel@tonic-gate request_on_command_line = B_TRUE;
500*0Sstevel@tonic-gate break;
501*0Sstevel@tonic-gate
502*0Sstevel@tonic-gate /* Size */
503*0Sstevel@tonic-gate case CREATE_SHORTOPT_SIZE:
504*0Sstevel@tonic-gate request_on_command_line = B_TRUE;
505*0Sstevel@tonic-gate error = copy_arg(
506*0Sstevel@tonic-gate argv[optind - 1], optarg, &arg_size);
507*0Sstevel@tonic-gate break;
508*0Sstevel@tonic-gate
509*0Sstevel@tonic-gate /* Input file */
510*0Sstevel@tonic-gate case CREATE_SHORTOPT_INPUTFILE:
511*0Sstevel@tonic-gate error = copy_arg(gettext("request/configuration file"),
512*0Sstevel@tonic-gate optarg, &arg_inputfile);
513*0Sstevel@tonic-gate break;
514*0Sstevel@tonic-gate
515*0Sstevel@tonic-gate default:
516*0Sstevel@tonic-gate /* Shouldn't be here! */
517*0Sstevel@tonic-gate volume_set_error(
518*0Sstevel@tonic-gate gettext("unexpected option: %c (%d)"), c, c);
519*0Sstevel@tonic-gate error = -1;
520*0Sstevel@tonic-gate }
521*0Sstevel@tonic-gate }
522*0Sstevel@tonic-gate }
523*0Sstevel@tonic-gate
524*0Sstevel@tonic-gate /*
525*0Sstevel@tonic-gate * Now that the arguments have been parsed, verify that
526*0Sstevel@tonic-gate * required options were specified.
527*0Sstevel@tonic-gate */
528*0Sstevel@tonic-gate if (!error) {
529*0Sstevel@tonic-gate /* Third invocation method -- two required arguments */
530*0Sstevel@tonic-gate if (request_on_command_line == B_TRUE) {
531*0Sstevel@tonic-gate if (arg_inputfile != NULL) {
532*0Sstevel@tonic-gate volume_set_error(
533*0Sstevel@tonic-gate gettext("invalid option(s) specified with input file"));
534*0Sstevel@tonic-gate error = -1;
535*0Sstevel@tonic-gate } else
536*0Sstevel@tonic-gate
537*0Sstevel@tonic-gate if (arg_size == NULL) {
538*0Sstevel@tonic-gate volume_set_error(gettext("no size specified"));
539*0Sstevel@tonic-gate error = -1;
540*0Sstevel@tonic-gate } else
541*0Sstevel@tonic-gate
542*0Sstevel@tonic-gate if (arg_diskset == NULL) {
543*0Sstevel@tonic-gate volume_set_error(gettext("no disk set specified"));
544*0Sstevel@tonic-gate error = -1;
545*0Sstevel@tonic-gate }
546*0Sstevel@tonic-gate } else
547*0Sstevel@tonic-gate
548*0Sstevel@tonic-gate /* First or second invocation method -- one required argument */
549*0Sstevel@tonic-gate if (arg_inputfile == NULL) {
550*0Sstevel@tonic-gate volume_set_error(gettext("missing required arguments"));
551*0Sstevel@tonic-gate error = -1;
552*0Sstevel@tonic-gate }
553*0Sstevel@tonic-gate
554*0Sstevel@tonic-gate /*
555*0Sstevel@tonic-gate * The CREATE_SHORTOPT_CONFIGFILE and
556*0Sstevel@tonic-gate * CREATE_SHORTOPT_COMMANDFILE arguments are mutually
557*0Sstevel@tonic-gate * exclusive. Verify that these were not both specified.
558*0Sstevel@tonic-gate */
559*0Sstevel@tonic-gate if (!error &&
560*0Sstevel@tonic-gate action & ACTION_OUTPUT_CONFIG &&
561*0Sstevel@tonic-gate action & ACTION_OUTPUT_COMMANDS) {
562*0Sstevel@tonic-gate volume_set_error(
563*0Sstevel@tonic-gate gettext("-%c and -%c are mutually exclusive"),
564*0Sstevel@tonic-gate CREATE_SHORTOPT_CONFIGFILE,
565*0Sstevel@tonic-gate CREATE_SHORTOPT_COMMANDFILE);
566*0Sstevel@tonic-gate error = -1;
567*0Sstevel@tonic-gate }
568*0Sstevel@tonic-gate }
569*0Sstevel@tonic-gate
570*0Sstevel@tonic-gate return (error);
571*0Sstevel@tonic-gate }
572*0Sstevel@tonic-gate
573*0Sstevel@tonic-gate /*
574*0Sstevel@tonic-gate * Parse the main command line options.
575*0Sstevel@tonic-gate *
576*0Sstevel@tonic-gate * @param argc
577*0Sstevel@tonic-gate * The number of arguments in the array
578*0Sstevel@tonic-gate *
579*0Sstevel@tonic-gate * @param argv
580*0Sstevel@tonic-gate * The argument array
581*0Sstevel@tonic-gate *
582*0Sstevel@tonic-gate * @return 0 on success, non-zero otherwise.
583*0Sstevel@tonic-gate */
584*0Sstevel@tonic-gate static int
parse_opts(int argc,char * argv[])585*0Sstevel@tonic-gate parse_opts(
586*0Sstevel@tonic-gate int argc,
587*0Sstevel@tonic-gate char *argv[])
588*0Sstevel@tonic-gate {
589*0Sstevel@tonic-gate int c;
590*0Sstevel@tonic-gate int error = 0;
591*0Sstevel@tonic-gate
592*0Sstevel@tonic-gate /* Examine next arg */
593*0Sstevel@tonic-gate while (!error && (c = getopt_ext(
594*0Sstevel@tonic-gate argc, argv, MAIN_SHORTOPTS)) != GETOPT_DONE_PARSING) {
595*0Sstevel@tonic-gate
596*0Sstevel@tonic-gate boolean_t handled;
597*0Sstevel@tonic-gate
598*0Sstevel@tonic-gate /* Check for args common to all scopes */
599*0Sstevel@tonic-gate error = handle_common_opts(c, &handled);
600*0Sstevel@tonic-gate
601*0Sstevel@tonic-gate if (error == 0 && handled == B_FALSE) {
602*0Sstevel@tonic-gate
603*0Sstevel@tonic-gate /* Check for args specific to this scope */
604*0Sstevel@tonic-gate switch (c) {
605*0Sstevel@tonic-gate
606*0Sstevel@tonic-gate /* Help */
607*0Sstevel@tonic-gate case COMMON_SHORTOPT_HELP:
608*0Sstevel@tonic-gate print_help_main(stdout);
609*0Sstevel@tonic-gate clean_up();
610*0Sstevel@tonic-gate exit(0);
611*0Sstevel@tonic-gate break;
612*0Sstevel@tonic-gate
613*0Sstevel@tonic-gate /* Non-option arg */
614*0Sstevel@tonic-gate case GETOPT_NON_OPTION_ARG:
615*0Sstevel@tonic-gate
616*0Sstevel@tonic-gate /* See if non-option arg is subcommand */
617*0Sstevel@tonic-gate if (strcmp(optarg, MAIN_SUBCMD_CREATE) == 0) {
618*0Sstevel@tonic-gate subcmd = SUBCMD_CREATE;
619*0Sstevel@tonic-gate error = parse_create_opts(argc, argv);
620*0Sstevel@tonic-gate } else {
621*0Sstevel@tonic-gate /* Argument not recognized */
622*0Sstevel@tonic-gate volume_set_error(
623*0Sstevel@tonic-gate gettext("%s: invalid argument"), optarg);
624*0Sstevel@tonic-gate error = -1;
625*0Sstevel@tonic-gate }
626*0Sstevel@tonic-gate break;
627*0Sstevel@tonic-gate
628*0Sstevel@tonic-gate default:
629*0Sstevel@tonic-gate /* Shouldn't be here! */
630*0Sstevel@tonic-gate volume_set_error(
631*0Sstevel@tonic-gate gettext("unexpected option: %c (%d)"), c, c);
632*0Sstevel@tonic-gate error = -1;
633*0Sstevel@tonic-gate }
634*0Sstevel@tonic-gate } else
635*0Sstevel@tonic-gate
636*0Sstevel@tonic-gate /*
637*0Sstevel@tonic-gate * Check invalid arguments to see if they are valid
638*0Sstevel@tonic-gate * options out of place.
639*0Sstevel@tonic-gate *
640*0Sstevel@tonic-gate * NOTE: IN THE FUTURE, A CODE BLOCK SIMILAR TO THIS
641*0Sstevel@tonic-gate * ONE SHOULD BE ADDED FOR EACH NEW SUBCOMMAND.
642*0Sstevel@tonic-gate */
643*0Sstevel@tonic-gate if (c == GETOPT_ERR_INVALID_OPT &&
644*0Sstevel@tonic-gate strchr(CREATE_SHORTOPTS, optopt) != NULL) {
645*0Sstevel@tonic-gate /* Provide a more enlightening error message */
646*0Sstevel@tonic-gate volume_set_error(
647*0Sstevel@tonic-gate gettext("-%c specified before create subcommand"), optopt);
648*0Sstevel@tonic-gate }
649*0Sstevel@tonic-gate }
650*0Sstevel@tonic-gate
651*0Sstevel@tonic-gate /* Parsing appears to be successful */
652*0Sstevel@tonic-gate if (!error) {
653*0Sstevel@tonic-gate
654*0Sstevel@tonic-gate /* Was a subcommand specified? */
655*0Sstevel@tonic-gate if (subcmd == SUBCMD_NONE) {
656*0Sstevel@tonic-gate volume_set_error(gettext("no subcommand specified"));
657*0Sstevel@tonic-gate error = -1;
658*0Sstevel@tonic-gate }
659*0Sstevel@tonic-gate }
660*0Sstevel@tonic-gate
661*0Sstevel@tonic-gate return (error);
662*0Sstevel@tonic-gate }
663*0Sstevel@tonic-gate
664*0Sstevel@tonic-gate /*
665*0Sstevel@tonic-gate * Convert a string containing a comma/space-separated list into a
666*0Sstevel@tonic-gate * dlist.
667*0Sstevel@tonic-gate *
668*0Sstevel@tonic-gate * @param string
669*0Sstevel@tonic-gate * a comma/space-separated list
670*0Sstevel@tonic-gate *
671*0Sstevel@tonic-gate * @param list
672*0Sstevel@tonic-gate * An exisiting dlist to append to, or NULL to create a
673*0Sstevel@tonic-gate * new list.
674*0Sstevel@tonic-gate *
675*0Sstevel@tonic-gate * @return The head node of the dlist_t, whether it was newly
676*0Sstevel@tonic-gate * created or passed in. On memory allocation error,
677*0Sstevel@tonic-gate * errno will be set and processing will stop.
678*0Sstevel@tonic-gate */
679*0Sstevel@tonic-gate static int
parse_tokenized_list(const char * string,dlist_t ** list)680*0Sstevel@tonic-gate parse_tokenized_list(
681*0Sstevel@tonic-gate const char *string,
682*0Sstevel@tonic-gate dlist_t **list)
683*0Sstevel@tonic-gate {
684*0Sstevel@tonic-gate char *stringdup;
685*0Sstevel@tonic-gate char *device;
686*0Sstevel@tonic-gate char *dup;
687*0Sstevel@tonic-gate dlist_t *item;
688*0Sstevel@tonic-gate int error = 0;
689*0Sstevel@tonic-gate
690*0Sstevel@tonic-gate /* Don't let strtok alter original argument */
691*0Sstevel@tonic-gate if ((stringdup = strdup(string)) == NULL) {
692*0Sstevel@tonic-gate error = ENOMEM;
693*0Sstevel@tonic-gate } else {
694*0Sstevel@tonic-gate
695*0Sstevel@tonic-gate /* For each device in the string list... */
696*0Sstevel@tonic-gate while ((device = strtok(stringdup, DEVICELISTDELIM)) != NULL) {
697*0Sstevel@tonic-gate
698*0Sstevel@tonic-gate /* Duplicate the device string */
699*0Sstevel@tonic-gate if ((dup = strdup(device)) == NULL) {
700*0Sstevel@tonic-gate error = ENOMEM;
701*0Sstevel@tonic-gate break;
702*0Sstevel@tonic-gate }
703*0Sstevel@tonic-gate
704*0Sstevel@tonic-gate /* Create new dlist_t for this device */
705*0Sstevel@tonic-gate if ((item = dlist_new_item((void *)dup)) == NULL) {
706*0Sstevel@tonic-gate error = ENOMEM;
707*0Sstevel@tonic-gate free(dup);
708*0Sstevel@tonic-gate break;
709*0Sstevel@tonic-gate }
710*0Sstevel@tonic-gate
711*0Sstevel@tonic-gate /* Append item to list */
712*0Sstevel@tonic-gate *list = dlist_append(item, *list, B_TRUE);
713*0Sstevel@tonic-gate
714*0Sstevel@tonic-gate /* strtok needs NULL pointer on subsequent calls */
715*0Sstevel@tonic-gate stringdup = NULL;
716*0Sstevel@tonic-gate }
717*0Sstevel@tonic-gate
718*0Sstevel@tonic-gate free(stringdup);
719*0Sstevel@tonic-gate }
720*0Sstevel@tonic-gate
721*0Sstevel@tonic-gate return (error);
722*0Sstevel@tonic-gate }
723*0Sstevel@tonic-gate
724*0Sstevel@tonic-gate /*
725*0Sstevel@tonic-gate * Parses the given verbosity level argument string.
726*0Sstevel@tonic-gate *
727*0Sstevel@tonic-gate * @param arg
728*0Sstevel@tonic-gate * A string representation of a verbosity level
729*0Sstevel@tonic-gate *
730*0Sstevel@tonic-gate * @param verbosity
731*0Sstevel@tonic-gate * RETURN: the verbosity level
732*0Sstevel@tonic-gate *
733*0Sstevel@tonic-gate * @return 0 if the given verbosity level string cannot
734*0Sstevel@tonic-gate * be interpreted, non-zero otherwise
735*0Sstevel@tonic-gate */
736*0Sstevel@tonic-gate static int
parse_verbose_arg(char * arg,int * verbosity)737*0Sstevel@tonic-gate parse_verbose_arg(
738*0Sstevel@tonic-gate char *arg,
739*0Sstevel@tonic-gate int *verbosity)
740*0Sstevel@tonic-gate {
741*0Sstevel@tonic-gate int level;
742*0Sstevel@tonic-gate
743*0Sstevel@tonic-gate /* Scan for int */
744*0Sstevel@tonic-gate if (sscanf(arg, "%d", &level) == 1) {
745*0Sstevel@tonic-gate
746*0Sstevel@tonic-gate /* Argument was an integer */
747*0Sstevel@tonic-gate switch (level) {
748*0Sstevel@tonic-gate case OUTPUT_QUIET:
749*0Sstevel@tonic-gate case OUTPUT_TERSE:
750*0Sstevel@tonic-gate case OUTPUT_VERBOSE:
751*0Sstevel@tonic-gate #ifdef DEBUG
752*0Sstevel@tonic-gate case OUTPUT_DEBUG:
753*0Sstevel@tonic-gate #endif
754*0Sstevel@tonic-gate
755*0Sstevel@tonic-gate *verbosity = level;
756*0Sstevel@tonic-gate return (0);
757*0Sstevel@tonic-gate }
758*0Sstevel@tonic-gate }
759*0Sstevel@tonic-gate
760*0Sstevel@tonic-gate volume_set_error(gettext("%s: invalid verbosity level"), arg);
761*0Sstevel@tonic-gate return (-1);
762*0Sstevel@tonic-gate }
763*0Sstevel@tonic-gate
764*0Sstevel@tonic-gate /*
765*0Sstevel@tonic-gate * Print the help message for the command.
766*0Sstevel@tonic-gate *
767*0Sstevel@tonic-gate * @param stream
768*0Sstevel@tonic-gate * stdout or stderr, as appropriate.
769*0Sstevel@tonic-gate */
770*0Sstevel@tonic-gate static void
print_help_create(FILE * stream)771*0Sstevel@tonic-gate print_help_create(
772*0Sstevel@tonic-gate FILE *stream)
773*0Sstevel@tonic-gate {
774*0Sstevel@tonic-gate print_usage_create(stream);
775*0Sstevel@tonic-gate
776*0Sstevel@tonic-gate /* BEGIN CSTYLED */
777*0Sstevel@tonic-gate fprintf(stream, gettext("\
778*0Sstevel@tonic-gate \n\
779*0Sstevel@tonic-gate Create Solaris Volume Manager volumes.\n\
780*0Sstevel@tonic-gate \n\
781*0Sstevel@tonic-gate -F <inputfile>\n\
782*0Sstevel@tonic-gate Specify the volume request or volume configuration file to\n\
783*0Sstevel@tonic-gate process.\n\
784*0Sstevel@tonic-gate \n\
785*0Sstevel@tonic-gate -s <set>\n\
786*0Sstevel@tonic-gate Specify the disk set to use when creating volumes.\n\
787*0Sstevel@tonic-gate \n\
788*0Sstevel@tonic-gate -S <size>\n\
789*0Sstevel@tonic-gate Specify the size of the volume to be created.\n\
790*0Sstevel@tonic-gate \n\
791*0Sstevel@tonic-gate -a <device1,device2,...>\n\
792*0Sstevel@tonic-gate Explicitly specify the devices that can be used in the\n\
793*0Sstevel@tonic-gate creation of this volume.\n\
794*0Sstevel@tonic-gate \n\
795*0Sstevel@tonic-gate -c Output the command script that would implement the specified or\n\
796*0Sstevel@tonic-gate generated volume configuration.\n\
797*0Sstevel@tonic-gate \n\
798*0Sstevel@tonic-gate -d Output the volume configuration that satisfies the specified or\n\
799*0Sstevel@tonic-gate generated volume request.\n\
800*0Sstevel@tonic-gate \n\
801*0Sstevel@tonic-gate -f Specify whether the volume should support automatic component\n\
802*0Sstevel@tonic-gate replacement after a fault.\n\
803*0Sstevel@tonic-gate \n\
804*0Sstevel@tonic-gate -n <name>\n\
805*0Sstevel@tonic-gate Specify the name of the new volume.\n\
806*0Sstevel@tonic-gate \n\
807*0Sstevel@tonic-gate -p <n>\n\
808*0Sstevel@tonic-gate Specify the number of required paths to the storage volume.\n\
809*0Sstevel@tonic-gate \n\
810*0Sstevel@tonic-gate -r <n>\n\
811*0Sstevel@tonic-gate Specify the redundancy level (0-4) of the data.\n\
812*0Sstevel@tonic-gate \n\
813*0Sstevel@tonic-gate -u <device1,device2,...>\n\
814*0Sstevel@tonic-gate Explicitly specify devices to exclude in the creation of this\n\
815*0Sstevel@tonic-gate volume.\n\
816*0Sstevel@tonic-gate \n\
817*0Sstevel@tonic-gate -v <value>\n\
818*0Sstevel@tonic-gate Specify the level of verbosity.\n\
819*0Sstevel@tonic-gate \n\
820*0Sstevel@tonic-gate -V Display program version information.\n\
821*0Sstevel@tonic-gate \n\
822*0Sstevel@tonic-gate -? Display help information.\n"));
823*0Sstevel@tonic-gate
824*0Sstevel@tonic-gate /* END CSTYLED */
825*0Sstevel@tonic-gate
826*0Sstevel@tonic-gate print_manual_reference(stream);
827*0Sstevel@tonic-gate }
828*0Sstevel@tonic-gate
829*0Sstevel@tonic-gate /*
830*0Sstevel@tonic-gate * Print the help message for the command.
831*0Sstevel@tonic-gate *
832*0Sstevel@tonic-gate * @param stream
833*0Sstevel@tonic-gate * stdout or stderr, as appropriate.
834*0Sstevel@tonic-gate */
835*0Sstevel@tonic-gate static void
print_help_main(FILE * stream)836*0Sstevel@tonic-gate print_help_main(
837*0Sstevel@tonic-gate FILE *stream)
838*0Sstevel@tonic-gate {
839*0Sstevel@tonic-gate print_usage_main(stream);
840*0Sstevel@tonic-gate
841*0Sstevel@tonic-gate /* BEGIN CSTYLED */
842*0Sstevel@tonic-gate fprintf(stream, gettext("\
843*0Sstevel@tonic-gate \n\
844*0Sstevel@tonic-gate Provide assistance, through automation, with common Solaris Volume\n\
845*0Sstevel@tonic-gate Manager tasks.\n\
846*0Sstevel@tonic-gate \n\
847*0Sstevel@tonic-gate -V Display program version information.\n\
848*0Sstevel@tonic-gate \n\
849*0Sstevel@tonic-gate -? Display help information. This option can follow <subcommand>\n\
850*0Sstevel@tonic-gate for subcommand-specific help.\n\
851*0Sstevel@tonic-gate \n\
852*0Sstevel@tonic-gate The accepted values for <subcommand> are:\n\
853*0Sstevel@tonic-gate \n\
854*0Sstevel@tonic-gate create Create Solaris Volume Manager volumes.\n"));
855*0Sstevel@tonic-gate /* END CSTYLED */
856*0Sstevel@tonic-gate
857*0Sstevel@tonic-gate print_manual_reference(stream);
858*0Sstevel@tonic-gate }
859*0Sstevel@tonic-gate
860*0Sstevel@tonic-gate /*
861*0Sstevel@tonic-gate * Print the help postscript for the command.
862*0Sstevel@tonic-gate *
863*0Sstevel@tonic-gate * @param stream
864*0Sstevel@tonic-gate * stdout or stderr, as appropriate.
865*0Sstevel@tonic-gate */
866*0Sstevel@tonic-gate static void
print_manual_reference(FILE * stream)867*0Sstevel@tonic-gate print_manual_reference(
868*0Sstevel@tonic-gate FILE *stream)
869*0Sstevel@tonic-gate {
870*0Sstevel@tonic-gate fprintf(stream, gettext("\nFor more information, see %s(1M).\n"),
871*0Sstevel@tonic-gate progname);
872*0Sstevel@tonic-gate }
873*0Sstevel@tonic-gate
874*0Sstevel@tonic-gate /*
875*0Sstevel@tonic-gate * Print the program usage to the given file stream.
876*0Sstevel@tonic-gate *
877*0Sstevel@tonic-gate * @param stream
878*0Sstevel@tonic-gate * stdout or stderr, as appropriate.
879*0Sstevel@tonic-gate */
880*0Sstevel@tonic-gate static void
print_usage(FILE * stream)881*0Sstevel@tonic-gate print_usage(
882*0Sstevel@tonic-gate FILE *stream)
883*0Sstevel@tonic-gate {
884*0Sstevel@tonic-gate switch (subcmd) {
885*0Sstevel@tonic-gate case SUBCMD_CREATE:
886*0Sstevel@tonic-gate print_usage_create(stream);
887*0Sstevel@tonic-gate break;
888*0Sstevel@tonic-gate
889*0Sstevel@tonic-gate case SUBCMD_NONE:
890*0Sstevel@tonic-gate default:
891*0Sstevel@tonic-gate print_usage_main(stream);
892*0Sstevel@tonic-gate }
893*0Sstevel@tonic-gate }
894*0Sstevel@tonic-gate
895*0Sstevel@tonic-gate /*
896*0Sstevel@tonic-gate * Print the program usage to the given file stream.
897*0Sstevel@tonic-gate *
898*0Sstevel@tonic-gate * @param stream
899*0Sstevel@tonic-gate * stdout or stderr, as appropriate.
900*0Sstevel@tonic-gate */
901*0Sstevel@tonic-gate static void
print_usage_create(FILE * stream)902*0Sstevel@tonic-gate print_usage_create(
903*0Sstevel@tonic-gate FILE *stream)
904*0Sstevel@tonic-gate {
905*0Sstevel@tonic-gate /* Create a blank the length of progname */
906*0Sstevel@tonic-gate char *blank = strdup(progname);
907*0Sstevel@tonic-gate memset(blank, ' ', strlen(blank) * sizeof (char));
908*0Sstevel@tonic-gate
909*0Sstevel@tonic-gate /* BEGIN CSTYLED */
910*0Sstevel@tonic-gate fprintf(stream, gettext("\
911*0Sstevel@tonic-gate Usage: %1$s create [-v <n>] [-c] -F <configfile>\n\
912*0Sstevel@tonic-gate %1$s create [-v <n>] [-c|-d] -F <requestfile>\n\
913*0Sstevel@tonic-gate %1$s create [-v <n>] [-c|-d]\n\
914*0Sstevel@tonic-gate %2$s [-f] [-n <name>] [-p <datapaths>] [-r <redundancy>]\n\
915*0Sstevel@tonic-gate %2$s [-a <available>[,<available>,...]]\n\
916*0Sstevel@tonic-gate %2$s [-u <unavailable>[,<unavailable>,...]]\n\
917*0Sstevel@tonic-gate %2$s -s <setname> -S <size>\n\
918*0Sstevel@tonic-gate %1$s create -V\n\
919*0Sstevel@tonic-gate %1$s create -?\n"), progname, blank);
920*0Sstevel@tonic-gate /* END CSTYLED */
921*0Sstevel@tonic-gate
922*0Sstevel@tonic-gate free(blank);
923*0Sstevel@tonic-gate }
924*0Sstevel@tonic-gate
925*0Sstevel@tonic-gate /*
926*0Sstevel@tonic-gate * Print the program usage to the given file stream.
927*0Sstevel@tonic-gate *
928*0Sstevel@tonic-gate * @param stream
929*0Sstevel@tonic-gate * stdout or stderr, as appropriate.
930*0Sstevel@tonic-gate */
931*0Sstevel@tonic-gate static void
print_usage_main(FILE * stream)932*0Sstevel@tonic-gate print_usage_main(
933*0Sstevel@tonic-gate FILE *stream)
934*0Sstevel@tonic-gate {
935*0Sstevel@tonic-gate /* BEGIN CSTYLED */
936*0Sstevel@tonic-gate fprintf(stream, gettext("\
937*0Sstevel@tonic-gate Usage: %1$s <subcommand> [-?] [options]\n\
938*0Sstevel@tonic-gate %1$s -V\n\
939*0Sstevel@tonic-gate %1$s -?\n"), progname);
940*0Sstevel@tonic-gate /* END CSTYLED */
941*0Sstevel@tonic-gate }
942*0Sstevel@tonic-gate
943*0Sstevel@tonic-gate /*
944*0Sstevel@tonic-gate * Print the program version to the given file stream.
945*0Sstevel@tonic-gate *
946*0Sstevel@tonic-gate * @param stream
947*0Sstevel@tonic-gate * stdout or stderr, as appropriate.
948*0Sstevel@tonic-gate */
949*0Sstevel@tonic-gate static int
print_version(FILE * stream)950*0Sstevel@tonic-gate print_version(
951*0Sstevel@tonic-gate FILE *stream)
952*0Sstevel@tonic-gate {
953*0Sstevel@tonic-gate int error = 0;
954*0Sstevel@tonic-gate struct utsname uname_info;
955*0Sstevel@tonic-gate
956*0Sstevel@tonic-gate if (uname(&uname_info) < 0) {
957*0Sstevel@tonic-gate error = -1;
958*0Sstevel@tonic-gate volume_set_error(gettext("could not determine version"));
959*0Sstevel@tonic-gate } else {
960*0Sstevel@tonic-gate fprintf(stream, gettext("%s %s"), progname, uname_info.version);
961*0Sstevel@tonic-gate }
962*0Sstevel@tonic-gate
963*0Sstevel@tonic-gate fprintf(stream, "\n");
964*0Sstevel@tonic-gate
965*0Sstevel@tonic-gate return (error);
966*0Sstevel@tonic-gate }
967*0Sstevel@tonic-gate
968*0Sstevel@tonic-gate /*
969*0Sstevel@tonic-gate * Get an xmlDocPtr by parsing the given file.
970*0Sstevel@tonic-gate *
971*0Sstevel@tonic-gate * @param file
972*0Sstevel@tonic-gate * The file to read
973*0Sstevel@tonic-gate *
974*0Sstevel@tonic-gate * @param valid_types
975*0Sstevel@tonic-gate * An array of the allowable root elements. If the root
976*0Sstevel@tonic-gate * element of the parsed XML file is not in this list, an
977*0Sstevel@tonic-gate * error is returned.
978*0Sstevel@tonic-gate *
979*0Sstevel@tonic-gate * @param doc
980*0Sstevel@tonic-gate * RETURN: the XML document
981*0Sstevel@tonic-gate *
982*0Sstevel@tonic-gate * @param root
983*0Sstevel@tonic-gate * RETURN: the root element of the document
984*0Sstevel@tonic-gate *
985*0Sstevel@tonic-gate * @return 0 if the given XML file was successfully parsed,
986*0Sstevel@tonic-gate * non-zero otherwise
987*0Sstevel@tonic-gate */
988*0Sstevel@tonic-gate static int
get_doc_from_file(char * file,char ** valid_types,xmlDocPtr * doc,char ** root)989*0Sstevel@tonic-gate get_doc_from_file(
990*0Sstevel@tonic-gate char *file,
991*0Sstevel@tonic-gate char **valid_types,
992*0Sstevel@tonic-gate xmlDocPtr *doc,
993*0Sstevel@tonic-gate char **root)
994*0Sstevel@tonic-gate {
995*0Sstevel@tonic-gate int error = 0;
996*0Sstevel@tonic-gate
997*0Sstevel@tonic-gate *root = NULL;
998*0Sstevel@tonic-gate
999*0Sstevel@tonic-gate /*
1000*0Sstevel@tonic-gate * Create XML doc by reading the specified file using the
1001*0Sstevel@tonic-gate * default SAX handler (which has been modified in init_xml())
1002*0Sstevel@tonic-gate */
1003*0Sstevel@tonic-gate *doc = xmlSAXParseFile((xmlSAXHandlerPtr)
1004*0Sstevel@tonic-gate &xmlDefaultSAXHandler, file, 0);
1005*0Sstevel@tonic-gate
1006*0Sstevel@tonic-gate if (*doc != NULL) {
1007*0Sstevel@tonic-gate int i;
1008*0Sstevel@tonic-gate xmlNodePtr root_elem = xmlDocGetRootElement(*doc);
1009*0Sstevel@tonic-gate
1010*0Sstevel@tonic-gate /* Is this a valid root element? */
1011*0Sstevel@tonic-gate for (i = 0; valid_types[i] != NULL; i++) {
1012*0Sstevel@tonic-gate if (xmlStrcmp(root_elem->name,
1013*0Sstevel@tonic-gate (const xmlChar *)valid_types[i]) == 0) {
1014*0Sstevel@tonic-gate *root = valid_types[i];
1015*0Sstevel@tonic-gate }
1016*0Sstevel@tonic-gate }
1017*0Sstevel@tonic-gate
1018*0Sstevel@tonic-gate /* Was a valid root element found? */
1019*0Sstevel@tonic-gate if (*root == NULL) {
1020*0Sstevel@tonic-gate xmlFreeDoc(*doc);
1021*0Sstevel@tonic-gate }
1022*0Sstevel@tonic-gate }
1023*0Sstevel@tonic-gate
1024*0Sstevel@tonic-gate /* Was a valid root element found? */
1025*0Sstevel@tonic-gate if (*root == NULL) {
1026*0Sstevel@tonic-gate volume_set_error(
1027*0Sstevel@tonic-gate gettext("%s: invalid or malformed XML file"), file);
1028*0Sstevel@tonic-gate error = -1;
1029*0Sstevel@tonic-gate }
1030*0Sstevel@tonic-gate
1031*0Sstevel@tonic-gate return (error);
1032*0Sstevel@tonic-gate }
1033*0Sstevel@tonic-gate
1034*0Sstevel@tonic-gate /*
1035*0Sstevel@tonic-gate * Creates a volume-request or volume-config XML document, based on the
1036*0Sstevel@tonic-gate * arguments passed into the command.
1037*0Sstevel@tonic-gate *
1038*0Sstevel@tonic-gate * @param doc
1039*0Sstevel@tonic-gate * RETURN: the XML document, or NULL if no valid document
1040*0Sstevel@tonic-gate * could be created.
1041*0Sstevel@tonic-gate *
1042*0Sstevel@tonic-gate * @param root
1043*0Sstevel@tonic-gate * RETURN: the root element of the document
1044*0Sstevel@tonic-gate *
1045*0Sstevel@tonic-gate * @return 0 if a volume-request or volume-config XML document
1046*0Sstevel@tonic-gate * could be read or created, non-zero otherwise
1047*0Sstevel@tonic-gate */
1048*0Sstevel@tonic-gate static int
get_volume_request_or_config(xmlDocPtr * doc,char ** root)1049*0Sstevel@tonic-gate get_volume_request_or_config(
1050*0Sstevel@tonic-gate xmlDocPtr *doc,
1051*0Sstevel@tonic-gate char **root)
1052*0Sstevel@tonic-gate {
1053*0Sstevel@tonic-gate int error = 0;
1054*0Sstevel@tonic-gate
1055*0Sstevel@tonic-gate if (arg_inputfile == NULL) {
1056*0Sstevel@tonic-gate /* Create a volume-request based on quality of service */
1057*0Sstevel@tonic-gate *doc = create_volume_request_XML();
1058*0Sstevel@tonic-gate
1059*0Sstevel@tonic-gate if (*doc == NULL) {
1060*0Sstevel@tonic-gate volume_set_error(gettext("error creating volume request"));
1061*0Sstevel@tonic-gate error = -1;
1062*0Sstevel@tonic-gate *root = NULL;
1063*0Sstevel@tonic-gate } else {
1064*0Sstevel@tonic-gate *root = ELEMENT_VOLUMEREQUEST;
1065*0Sstevel@tonic-gate }
1066*0Sstevel@tonic-gate } else {
1067*0Sstevel@tonic-gate char *valid[] = {
1068*0Sstevel@tonic-gate ELEMENT_VOLUMEREQUEST,
1069*0Sstevel@tonic-gate ELEMENT_VOLUMECONFIG,
1070*0Sstevel@tonic-gate NULL
1071*0Sstevel@tonic-gate };
1072*0Sstevel@tonic-gate
1073*0Sstevel@tonic-gate error = get_doc_from_file(arg_inputfile, valid, doc, root);
1074*0Sstevel@tonic-gate }
1075*0Sstevel@tonic-gate
1076*0Sstevel@tonic-gate return (error);
1077*0Sstevel@tonic-gate }
1078*0Sstevel@tonic-gate
1079*0Sstevel@tonic-gate /*
1080*0Sstevel@tonic-gate * Handle processing of the given meta* commands. Commands are
1081*0Sstevel@tonic-gate * written to a file, the file is optionally executed, and optionally
1082*0Sstevel@tonic-gate * deleted.
1083*0Sstevel@tonic-gate *
1084*0Sstevel@tonic-gate * @param commands
1085*0Sstevel@tonic-gate * The commands to write to the command script file.
1086*0Sstevel@tonic-gate *
1087*0Sstevel@tonic-gate * @return 0 on success, non-zero otherwise.
1088*0Sstevel@tonic-gate */
1089*0Sstevel@tonic-gate static int
handle_commands(char * commands)1090*0Sstevel@tonic-gate handle_commands(
1091*0Sstevel@tonic-gate char *commands)
1092*0Sstevel@tonic-gate {
1093*0Sstevel@tonic-gate int error = 0;
1094*0Sstevel@tonic-gate
1095*0Sstevel@tonic-gate if (action & ACTION_OUTPUT_COMMANDS) {
1096*0Sstevel@tonic-gate printf("%s", commands);
1097*0Sstevel@tonic-gate }
1098*0Sstevel@tonic-gate
1099*0Sstevel@tonic-gate if (action & ACTION_EXECUTE) {
1100*0Sstevel@tonic-gate
1101*0Sstevel@tonic-gate /* Write a temporary file with 744 permissions */
1102*0Sstevel@tonic-gate if ((error = write_temp_file(commands,
1103*0Sstevel@tonic-gate S_IRWXU | S_IRGRP | S_IROTH, &commandfile)) == 0) {
1104*0Sstevel@tonic-gate
1105*0Sstevel@tonic-gate char *command;
1106*0Sstevel@tonic-gate
1107*0Sstevel@tonic-gate /* Create command line to execute */
1108*0Sstevel@tonic-gate if (get_max_verbosity() >= OUTPUT_VERBOSE) {
1109*0Sstevel@tonic-gate /* Verbose */
1110*0Sstevel@tonic-gate command = stralloccat(3,
1111*0Sstevel@tonic-gate commandfile, " ", COMMAND_VERBOSE_FLAG);
1112*0Sstevel@tonic-gate } else {
1113*0Sstevel@tonic-gate /* Terse */
1114*0Sstevel@tonic-gate command = strdup(commandfile);
1115*0Sstevel@tonic-gate }
1116*0Sstevel@tonic-gate
1117*0Sstevel@tonic-gate if (command == NULL) {
1118*0Sstevel@tonic-gate volume_set_error(gettext("could not allocate memory"));
1119*0Sstevel@tonic-gate error = -1;
1120*0Sstevel@tonic-gate } else {
1121*0Sstevel@tonic-gate
1122*0Sstevel@tonic-gate oprintf(OUTPUT_VERBOSE,
1123*0Sstevel@tonic-gate gettext("Executing command script: %s\n"), command);
1124*0Sstevel@tonic-gate
1125*0Sstevel@tonic-gate /* Execute command */
1126*0Sstevel@tonic-gate switch (error = system(command)) {
1127*0Sstevel@tonic-gate /* system() failed */
1128*0Sstevel@tonic-gate case -1:
1129*0Sstevel@tonic-gate error = errno;
1130*0Sstevel@tonic-gate break;
1131*0Sstevel@tonic-gate
1132*0Sstevel@tonic-gate /* Command succeded */
1133*0Sstevel@tonic-gate case 0:
1134*0Sstevel@tonic-gate break;
1135*0Sstevel@tonic-gate
1136*0Sstevel@tonic-gate /* Command failed */
1137*0Sstevel@tonic-gate default:
1138*0Sstevel@tonic-gate volume_set_error(
1139*0Sstevel@tonic-gate /* CSTYLED */
1140*0Sstevel@tonic-gate gettext("execution of command script failed with status %d"),
1141*0Sstevel@tonic-gate WEXITSTATUS(error));
1142*0Sstevel@tonic-gate error = -1;
1143*0Sstevel@tonic-gate }
1144*0Sstevel@tonic-gate free(command);
1145*0Sstevel@tonic-gate }
1146*0Sstevel@tonic-gate }
1147*0Sstevel@tonic-gate }
1148*0Sstevel@tonic-gate
1149*0Sstevel@tonic-gate return (error);
1150*0Sstevel@tonic-gate }
1151*0Sstevel@tonic-gate
1152*0Sstevel@tonic-gate /*
1153*0Sstevel@tonic-gate * Handle processing of the given volume-config devconfig_t. The
1154*0Sstevel@tonic-gate * devconfig_t is first converted to XML. Then, depending
1155*0Sstevel@tonic-gate * on user input to the command, the XML is either written to a file
1156*0Sstevel@tonic-gate * or converted to a command script and passed on to
1157*0Sstevel@tonic-gate * handle_commands().
1158*0Sstevel@tonic-gate *
1159*0Sstevel@tonic-gate * @param config
1160*0Sstevel@tonic-gate * A devconfig_t representing a valid volume-config.
1161*0Sstevel@tonic-gate *
1162*0Sstevel@tonic-gate * @return 0 on success, non-zero otherwise.
1163*0Sstevel@tonic-gate */
1164*0Sstevel@tonic-gate static int
handle_config(devconfig_t * config)1165*0Sstevel@tonic-gate handle_config(
1166*0Sstevel@tonic-gate devconfig_t *config)
1167*0Sstevel@tonic-gate {
1168*0Sstevel@tonic-gate int error;
1169*0Sstevel@tonic-gate xmlDocPtr doc;
1170*0Sstevel@tonic-gate
1171*0Sstevel@tonic-gate /* Get the xml document for the config */
1172*0Sstevel@tonic-gate if ((error = config_to_xml(config, &doc)) == 0) {
1173*0Sstevel@tonic-gate
1174*0Sstevel@tonic-gate /* Get the text dump */
1175*0Sstevel@tonic-gate xmlChar *text;
1176*0Sstevel@tonic-gate xmlDocDumpFormatMemory(doc, &text, NULL, 1);
1177*0Sstevel@tonic-gate
1178*0Sstevel@tonic-gate /* Should we output the config file? */
1179*0Sstevel@tonic-gate if (action & ACTION_OUTPUT_CONFIG) {
1180*0Sstevel@tonic-gate printf("%s", text);
1181*0Sstevel@tonic-gate } else {
1182*0Sstevel@tonic-gate oprintf(OUTPUT_DEBUG,
1183*0Sstevel@tonic-gate gettext("Generated volume-config:\n%s"), text);
1184*0Sstevel@tonic-gate }
1185*0Sstevel@tonic-gate
1186*0Sstevel@tonic-gate xmlFree(text);
1187*0Sstevel@tonic-gate
1188*0Sstevel@tonic-gate /* Proceed to command generation? */
1189*0Sstevel@tonic-gate if (action & ACTION_OUTPUT_COMMANDS ||
1190*0Sstevel@tonic-gate action & ACTION_EXECUTE) {
1191*0Sstevel@tonic-gate char *commands;
1192*0Sstevel@tonic-gate
1193*0Sstevel@tonic-gate /* Get command script from the file */
1194*0Sstevel@tonic-gate if ((error = xml_to_commands(doc, &commands)) == 0) {
1195*0Sstevel@tonic-gate if (commands == NULL) {
1196*0Sstevel@tonic-gate volume_set_error(
1197*0Sstevel@tonic-gate gettext("could not convert XML to commands"));
1198*0Sstevel@tonic-gate error = -1;
1199*0Sstevel@tonic-gate } else {
1200*0Sstevel@tonic-gate error = handle_commands(commands);
1201*0Sstevel@tonic-gate free(commands);
1202*0Sstevel@tonic-gate }
1203*0Sstevel@tonic-gate }
1204*0Sstevel@tonic-gate }
1205*0Sstevel@tonic-gate
1206*0Sstevel@tonic-gate xmlFreeDoc(doc);
1207*0Sstevel@tonic-gate }
1208*0Sstevel@tonic-gate
1209*0Sstevel@tonic-gate return (error);
1210*0Sstevel@tonic-gate }
1211*0Sstevel@tonic-gate
1212*0Sstevel@tonic-gate /*
1213*0Sstevel@tonic-gate * Handle processing of the given volume-request request_t and
1214*0Sstevel@tonic-gate * volume-defaults defaults_t. A layout is generated from these
1215*0Sstevel@tonic-gate * structures and the resulting volume-config devconfig_t is passed on
1216*0Sstevel@tonic-gate * to handle_config().
1217*0Sstevel@tonic-gate *
1218*0Sstevel@tonic-gate * @param request
1219*0Sstevel@tonic-gate * A request_t representing a valid volume-request.
1220*0Sstevel@tonic-gate *
1221*0Sstevel@tonic-gate * @param defaults
1222*0Sstevel@tonic-gate * A defaults_t representing a valid volume-defaults.
1223*0Sstevel@tonic-gate *
1224*0Sstevel@tonic-gate * @return 0 on success, non-zero otherwise.
1225*0Sstevel@tonic-gate */
1226*0Sstevel@tonic-gate static int
handle_request(request_t * request,defaults_t * defaults)1227*0Sstevel@tonic-gate handle_request(
1228*0Sstevel@tonic-gate request_t *request,
1229*0Sstevel@tonic-gate defaults_t *defaults)
1230*0Sstevel@tonic-gate {
1231*0Sstevel@tonic-gate int error;
1232*0Sstevel@tonic-gate
1233*0Sstevel@tonic-gate /* Get layout for given request and system defaults */
1234*0Sstevel@tonic-gate if ((error = get_layout(request, defaults)) == 0) {
1235*0Sstevel@tonic-gate
1236*0Sstevel@tonic-gate /* Retrieve resulting volume config */
1237*0Sstevel@tonic-gate devconfig_t *config = request_get_diskset_config(request);
1238*0Sstevel@tonic-gate
1239*0Sstevel@tonic-gate if (config != NULL) {
1240*0Sstevel@tonic-gate error = handle_config(config);
1241*0Sstevel@tonic-gate }
1242*0Sstevel@tonic-gate }
1243*0Sstevel@tonic-gate
1244*0Sstevel@tonic-gate return (error);
1245*0Sstevel@tonic-gate }
1246*0Sstevel@tonic-gate
1247*0Sstevel@tonic-gate /*
1248*0Sstevel@tonic-gate * Write the given text to a temporary file with the given
1249*0Sstevel@tonic-gate * permissions. If the file already exists, return an error.
1250*0Sstevel@tonic-gate *
1251*0Sstevel@tonic-gate * @param text
1252*0Sstevel@tonic-gate * The text to write to the file.
1253*0Sstevel@tonic-gate *
1254*0Sstevel@tonic-gate * @param mode
1255*0Sstevel@tonic-gate * The permissions to give the file, passed to chmod(2).
1256*0Sstevel@tonic-gate *
1257*0Sstevel@tonic-gate * @param file
1258*0Sstevel@tonic-gate * RETURN: The name of the file written. Must be
1259*0Sstevel@tonic-gate * free()d.
1260*0Sstevel@tonic-gate *
1261*0Sstevel@tonic-gate * @return 0 on success, non-zero otherwise.
1262*0Sstevel@tonic-gate */
1263*0Sstevel@tonic-gate static int
write_temp_file(char * text,mode_t mode,char ** file)1264*0Sstevel@tonic-gate write_temp_file(
1265*0Sstevel@tonic-gate char *text,
1266*0Sstevel@tonic-gate mode_t mode,
1267*0Sstevel@tonic-gate char **file)
1268*0Sstevel@tonic-gate {
1269*0Sstevel@tonic-gate int error = 0;
1270*0Sstevel@tonic-gate
1271*0Sstevel@tonic-gate /*
1272*0Sstevel@tonic-gate * Create temporary file name -- "XXXXXX" is replaced with
1273*0Sstevel@tonic-gate * unique char sequence by mkstemp()
1274*0Sstevel@tonic-gate */
1275*0Sstevel@tonic-gate *file = stralloccat(3, "/tmp/", progname, "XXXXXX");
1276*0Sstevel@tonic-gate
1277*0Sstevel@tonic-gate if (*file == NULL) {
1278*0Sstevel@tonic-gate volume_set_error(gettext("out of memory"));
1279*0Sstevel@tonic-gate error = -1;
1280*0Sstevel@tonic-gate } else {
1281*0Sstevel@tonic-gate int fildes;
1282*0Sstevel@tonic-gate FILE *out = NULL;
1283*0Sstevel@tonic-gate
1284*0Sstevel@tonic-gate /* Open temp file */
1285*0Sstevel@tonic-gate if ((fildes = mkstemp(*file)) != -1) {
1286*0Sstevel@tonic-gate out = fdopen(fildes, "w");
1287*0Sstevel@tonic-gate }
1288*0Sstevel@tonic-gate
1289*0Sstevel@tonic-gate if (out == NULL) {
1290*0Sstevel@tonic-gate volume_set_error(gettext(
1291*0Sstevel@tonic-gate "could not open file for writing: %s"), *file);
1292*0Sstevel@tonic-gate error = -1;
1293*0Sstevel@tonic-gate } else {
1294*0Sstevel@tonic-gate
1295*0Sstevel@tonic-gate fprintf(out, "%s", text);
1296*0Sstevel@tonic-gate fclose(out);
1297*0Sstevel@tonic-gate
1298*0Sstevel@tonic-gate if (mode != 0) {
1299*0Sstevel@tonic-gate if (chmod(*file, mode)) {
1300*0Sstevel@tonic-gate volume_set_error(
1301*0Sstevel@tonic-gate gettext("could not change permissions of file: %s"),
1302*0Sstevel@tonic-gate *file);
1303*0Sstevel@tonic-gate error = -1;
1304*0Sstevel@tonic-gate }
1305*0Sstevel@tonic-gate }
1306*0Sstevel@tonic-gate
1307*0Sstevel@tonic-gate /* Remove file on error */
1308*0Sstevel@tonic-gate if (error != 0) {
1309*0Sstevel@tonic-gate unlink(*file);
1310*0Sstevel@tonic-gate }
1311*0Sstevel@tonic-gate }
1312*0Sstevel@tonic-gate
1313*0Sstevel@tonic-gate /* Free *file on error */
1314*0Sstevel@tonic-gate if (error != 0) {
1315*0Sstevel@tonic-gate free(*file);
1316*0Sstevel@tonic-gate *file = NULL;
1317*0Sstevel@tonic-gate }
1318*0Sstevel@tonic-gate }
1319*0Sstevel@tonic-gate
1320*0Sstevel@tonic-gate return (error);
1321*0Sstevel@tonic-gate }
1322*0Sstevel@tonic-gate
1323*0Sstevel@tonic-gate /*
1324*0Sstevel@tonic-gate * Main entry to metassist. See the print_usage_* functions* for
1325*0Sstevel@tonic-gate * usage.
1326*0Sstevel@tonic-gate *
1327*0Sstevel@tonic-gate * @return 0 on successful exit, non-zero otherwise
1328*0Sstevel@tonic-gate */
1329*0Sstevel@tonic-gate int
main(int argc,char * argv[])1330*0Sstevel@tonic-gate main(
1331*0Sstevel@tonic-gate int argc,
1332*0Sstevel@tonic-gate char *argv[])
1333*0Sstevel@tonic-gate {
1334*0Sstevel@tonic-gate int error = 0;
1335*0Sstevel@tonic-gate int printusage = 0;
1336*0Sstevel@tonic-gate
1337*0Sstevel@tonic-gate #ifdef DEBUG
1338*0Sstevel@tonic-gate time_t start = time(NULL);
1339*0Sstevel@tonic-gate #endif
1340*0Sstevel@tonic-gate
1341*0Sstevel@tonic-gate /*
1342*0Sstevel@tonic-gate * Get the locale set up before calling any other routines
1343*0Sstevel@tonic-gate * with messages to ouput. Just in case we're not in a build
1344*0Sstevel@tonic-gate * environment, make sure that TEXT_DOMAIN gets set to
1345*0Sstevel@tonic-gate * something.
1346*0Sstevel@tonic-gate */
1347*0Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
1348*0Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST"
1349*0Sstevel@tonic-gate #endif
1350*0Sstevel@tonic-gate (void) setlocale(LC_ALL, "");
1351*0Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN);
1352*0Sstevel@tonic-gate
1353*0Sstevel@tonic-gate /* Set program name, strip directory */
1354*0Sstevel@tonic-gate if ((progname = strrchr(argv[0], '/')) != NULL) {
1355*0Sstevel@tonic-gate progname++;
1356*0Sstevel@tonic-gate } else {
1357*0Sstevel@tonic-gate progname = argv[0];
1358*0Sstevel@tonic-gate }
1359*0Sstevel@tonic-gate
1360*0Sstevel@tonic-gate /* Set up signal handlers to exit gracefully */
1361*0Sstevel@tonic-gate {
1362*0Sstevel@tonic-gate struct sigaction act;
1363*0Sstevel@tonic-gate act.sa_handler = interrupthandler;
1364*0Sstevel@tonic-gate sigemptyset(&act.sa_mask);
1365*0Sstevel@tonic-gate act.sa_flags = 0;
1366*0Sstevel@tonic-gate sigaction(SIGHUP, &act, (struct sigaction *)0);
1367*0Sstevel@tonic-gate sigaction(SIGINT, &act, (struct sigaction *)0);
1368*0Sstevel@tonic-gate sigaction(SIGQUIT, &act, (struct sigaction *)0);
1369*0Sstevel@tonic-gate sigaction(SIGTERM, &act, (struct sigaction *)0);
1370*0Sstevel@tonic-gate }
1371*0Sstevel@tonic-gate
1372*0Sstevel@tonic-gate /* Set default verbosity level */
1373*0Sstevel@tonic-gate set_max_verbosity(OUTPUT_TERSE, stderr);
1374*0Sstevel@tonic-gate
1375*0Sstevel@tonic-gate /* Verify we're running as root */
1376*0Sstevel@tonic-gate if (geteuid() != 0) {
1377*0Sstevel@tonic-gate volume_set_error(gettext("must be run as root"));
1378*0Sstevel@tonic-gate error = -1;
1379*0Sstevel@tonic-gate } else {
1380*0Sstevel@tonic-gate
1381*0Sstevel@tonic-gate /* Disable error messages from getopt */
1382*0Sstevel@tonic-gate opterr = 0;
1383*0Sstevel@tonic-gate
1384*0Sstevel@tonic-gate /* Parse command-line options */
1385*0Sstevel@tonic-gate if ((error = parse_opts(argc, argv)) == 0) {
1386*0Sstevel@tonic-gate xmlDocPtr doc;
1387*0Sstevel@tonic-gate char *root;
1388*0Sstevel@tonic-gate
1389*0Sstevel@tonic-gate /* Initialize XML defaults */
1390*0Sstevel@tonic-gate init_xml();
1391*0Sstevel@tonic-gate
1392*0Sstevel@tonic-gate /* Read volume-request/config file */
1393*0Sstevel@tonic-gate if ((error = get_volume_request_or_config(&doc, &root)) == 0) {
1394*0Sstevel@tonic-gate
1395*0Sstevel@tonic-gate /* Is this a volume-config? */
1396*0Sstevel@tonic-gate if (strcmp(root, ELEMENT_VOLUMECONFIG) == 0) {
1397*0Sstevel@tonic-gate
1398*0Sstevel@tonic-gate /* Was the -d flag specified? */
1399*0Sstevel@tonic-gate if (action & ACTION_OUTPUT_CONFIG) {
1400*0Sstevel@tonic-gate /* -d cannot be used with -F <configfile> */
1401*0Sstevel@tonic-gate volume_set_error(gettext(
1402*0Sstevel@tonic-gate "-%c incompatible with -%c <configfile>"),
1403*0Sstevel@tonic-gate CREATE_SHORTOPT_CONFIGFILE,
1404*0Sstevel@tonic-gate CREATE_SHORTOPT_INPUTFILE);
1405*0Sstevel@tonic-gate error = -1;
1406*0Sstevel@tonic-gate printusage = 1;
1407*0Sstevel@tonic-gate } else {
1408*0Sstevel@tonic-gate devconfig_t *config;
1409*0Sstevel@tonic-gate if ((error = xml_to_config(doc, &config)) == 0) {
1410*0Sstevel@tonic-gate error = handle_config(config);
1411*0Sstevel@tonic-gate free_devconfig(config);
1412*0Sstevel@tonic-gate }
1413*0Sstevel@tonic-gate }
1414*0Sstevel@tonic-gate } else
1415*0Sstevel@tonic-gate
1416*0Sstevel@tonic-gate /* Is this a volume-request? */
1417*0Sstevel@tonic-gate if (strcmp(root, ELEMENT_VOLUMEREQUEST) == 0) {
1418*0Sstevel@tonic-gate request_t *request;
1419*0Sstevel@tonic-gate
1420*0Sstevel@tonic-gate if ((error = xml_to_request(doc, &request)) == 0) {
1421*0Sstevel@tonic-gate
1422*0Sstevel@tonic-gate xmlDocPtr defaults_doc;
1423*0Sstevel@tonic-gate char *valid[] = {
1424*0Sstevel@tonic-gate ELEMENT_VOLUMEDEFAULTS,
1425*0Sstevel@tonic-gate NULL
1426*0Sstevel@tonic-gate };
1427*0Sstevel@tonic-gate
1428*0Sstevel@tonic-gate /* Read defaults file */
1429*0Sstevel@tonic-gate if ((error = get_doc_from_file(VOLUME_DEFAULTS_LOC,
1430*0Sstevel@tonic-gate valid, &defaults_doc, &root)) == 0) {
1431*0Sstevel@tonic-gate
1432*0Sstevel@tonic-gate defaults_t *defaults;
1433*0Sstevel@tonic-gate
1434*0Sstevel@tonic-gate oprintf(OUTPUT_DEBUG,
1435*0Sstevel@tonic-gate gettext("Using defaults file: %s\n"),
1436*0Sstevel@tonic-gate VOLUME_DEFAULTS_LOC);
1437*0Sstevel@tonic-gate
1438*0Sstevel@tonic-gate /* Parse defaults XML */
1439*0Sstevel@tonic-gate if ((error = xml_to_defaults(
1440*0Sstevel@tonic-gate defaults_doc, &defaults)) == 0) {
1441*0Sstevel@tonic-gate error = handle_request(request, defaults);
1442*0Sstevel@tonic-gate free_defaults(defaults);
1443*0Sstevel@tonic-gate }
1444*0Sstevel@tonic-gate
1445*0Sstevel@tonic-gate xmlFreeDoc(defaults_doc);
1446*0Sstevel@tonic-gate }
1447*0Sstevel@tonic-gate
1448*0Sstevel@tonic-gate free_request(request);
1449*0Sstevel@tonic-gate }
1450*0Sstevel@tonic-gate }
1451*0Sstevel@tonic-gate
1452*0Sstevel@tonic-gate xmlFreeDoc(doc);
1453*0Sstevel@tonic-gate }
1454*0Sstevel@tonic-gate } else {
1455*0Sstevel@tonic-gate printusage = 1;
1456*0Sstevel@tonic-gate }
1457*0Sstevel@tonic-gate }
1458*0Sstevel@tonic-gate
1459*0Sstevel@tonic-gate /* Handle any errors that were propogated */
1460*0Sstevel@tonic-gate if (error != 0) {
1461*0Sstevel@tonic-gate char *message = get_error_string(error);
1462*0Sstevel@tonic-gate
1463*0Sstevel@tonic-gate if (message != NULL && strlen(message)) {
1464*0Sstevel@tonic-gate fprintf(stderr, "%s: %s\n", progname, message);
1465*0Sstevel@tonic-gate
1466*0Sstevel@tonic-gate if (printusage) {
1467*0Sstevel@tonic-gate fprintf(stderr, "\n");
1468*0Sstevel@tonic-gate }
1469*0Sstevel@tonic-gate }
1470*0Sstevel@tonic-gate
1471*0Sstevel@tonic-gate if (printusage) {
1472*0Sstevel@tonic-gate print_usage(stderr);
1473*0Sstevel@tonic-gate }
1474*0Sstevel@tonic-gate }
1475*0Sstevel@tonic-gate
1476*0Sstevel@tonic-gate #ifdef DEBUG
1477*0Sstevel@tonic-gate /* Print run report to stderr if METASSIST_DEBUG is set */
1478*0Sstevel@tonic-gate if (getenv(METASSIST_DEBUG_ENV) != NULL) {
1479*0Sstevel@tonic-gate time_t end = time(NULL);
1480*0Sstevel@tonic-gate struct tm *time;
1481*0Sstevel@tonic-gate int i;
1482*0Sstevel@tonic-gate #define TIMEFMT "%8s: %.2d:%.2d:%.2d\n"
1483*0Sstevel@tonic-gate
1484*0Sstevel@tonic-gate fprintf(stderr, " Command:");
1485*0Sstevel@tonic-gate for (i = 0; i < argc; i++) {
1486*0Sstevel@tonic-gate fprintf(stderr, " %s", argv[i]);
1487*0Sstevel@tonic-gate }
1488*0Sstevel@tonic-gate fprintf(stderr, "\n");
1489*0Sstevel@tonic-gate
1490*0Sstevel@tonic-gate fprintf(stderr, " Version: ");
1491*0Sstevel@tonic-gate print_version(stderr);
1492*0Sstevel@tonic-gate
1493*0Sstevel@tonic-gate time = localtime(&start);
1494*0Sstevel@tonic-gate fprintf(stderr, TIMEFMT, "Start",
1495*0Sstevel@tonic-gate time->tm_hour, time->tm_min, time->tm_sec);
1496*0Sstevel@tonic-gate
1497*0Sstevel@tonic-gate time = localtime(&end);
1498*0Sstevel@tonic-gate fprintf(stderr, TIMEFMT, "End",
1499*0Sstevel@tonic-gate time->tm_hour, time->tm_min, time->tm_sec);
1500*0Sstevel@tonic-gate
1501*0Sstevel@tonic-gate end -= start;
1502*0Sstevel@tonic-gate time = gmtime(&end);
1503*0Sstevel@tonic-gate fprintf(stderr, TIMEFMT, "Duration",
1504*0Sstevel@tonic-gate time->tm_hour, time->tm_min, time->tm_sec);
1505*0Sstevel@tonic-gate }
1506*0Sstevel@tonic-gate #endif
1507*0Sstevel@tonic-gate
1508*0Sstevel@tonic-gate clean_up();
1509*0Sstevel@tonic-gate
1510*0Sstevel@tonic-gate return (error != 0);
1511*0Sstevel@tonic-gate }
1512