xref: /onnv-gate/usr/src/cmd/iscsiadm/cmdparse.c (revision 7836:4e95154b5b7a)
1*7836SJohn.Forte@Sun.COM /*
2*7836SJohn.Forte@Sun.COM  * CDDL HEADER START
3*7836SJohn.Forte@Sun.COM  *
4*7836SJohn.Forte@Sun.COM  * The contents of this file are subject to the terms of the
5*7836SJohn.Forte@Sun.COM  * Common Development and Distribution License (the "License").
6*7836SJohn.Forte@Sun.COM  * You may not use this file except in compliance with the License.
7*7836SJohn.Forte@Sun.COM  *
8*7836SJohn.Forte@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*7836SJohn.Forte@Sun.COM  * or http://www.opensolaris.org/os/licensing.
10*7836SJohn.Forte@Sun.COM  * See the License for the specific language governing permissions
11*7836SJohn.Forte@Sun.COM  * and limitations under the License.
12*7836SJohn.Forte@Sun.COM  *
13*7836SJohn.Forte@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
14*7836SJohn.Forte@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*7836SJohn.Forte@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
16*7836SJohn.Forte@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
17*7836SJohn.Forte@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
18*7836SJohn.Forte@Sun.COM  *
19*7836SJohn.Forte@Sun.COM  * CDDL HEADER END
20*7836SJohn.Forte@Sun.COM  */
21*7836SJohn.Forte@Sun.COM /*
22*7836SJohn.Forte@Sun.COM  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23*7836SJohn.Forte@Sun.COM  * Use is subject to license terms.
24*7836SJohn.Forte@Sun.COM  */
25*7836SJohn.Forte@Sun.COM 
26*7836SJohn.Forte@Sun.COM #include <stdlib.h>
27*7836SJohn.Forte@Sun.COM #include <stdio.h>
28*7836SJohn.Forte@Sun.COM #include <sys/types.h>
29*7836SJohn.Forte@Sun.COM #include <unistd.h>
30*7836SJohn.Forte@Sun.COM #include <libintl.h>
31*7836SJohn.Forte@Sun.COM #include <errno.h>
32*7836SJohn.Forte@Sun.COM #include <string.h>
33*7836SJohn.Forte@Sun.COM #include <assert.h>
34*7836SJohn.Forte@Sun.COM #include <getopt.h>
35*7836SJohn.Forte@Sun.COM #include "cmdparse.h"
36*7836SJohn.Forte@Sun.COM 
37*7836SJohn.Forte@Sun.COM /* Usage types */
38*7836SJohn.Forte@Sun.COM #define	GENERAL_USAGE	1
39*7836SJohn.Forte@Sun.COM #define	HELP_USAGE	2
40*7836SJohn.Forte@Sun.COM #define	DETAIL_USAGE	3
41*7836SJohn.Forte@Sun.COM 
42*7836SJohn.Forte@Sun.COM /* printable ascii character set len */
43*7836SJohn.Forte@Sun.COM #define	MAXOPTIONS	(uint_t)('~' - '!' + 1)
44*7836SJohn.Forte@Sun.COM 
45*7836SJohn.Forte@Sun.COM /*
46*7836SJohn.Forte@Sun.COM  * MAXOPTIONSTRING is the max length of the options string used in getopt and
47*7836SJohn.Forte@Sun.COM  * will be the printable character set + ':' for each character,
48*7836SJohn.Forte@Sun.COM  * providing for options with arguments. e.g. "t:Cs:hglr:"
49*7836SJohn.Forte@Sun.COM  */
50*7836SJohn.Forte@Sun.COM #define	MAXOPTIONSTRING		MAXOPTIONS * 2
51*7836SJohn.Forte@Sun.COM 
52*7836SJohn.Forte@Sun.COM /* standard command options table to support -?, -V */
53*7836SJohn.Forte@Sun.COM struct option standardCmdOptions[] = {
54*7836SJohn.Forte@Sun.COM 	{"help", no_argument, NULL, '?'},
55*7836SJohn.Forte@Sun.COM 	{"version", no_argument, NULL, 'V'},
56*7836SJohn.Forte@Sun.COM 	{NULL, 0, NULL, 0}
57*7836SJohn.Forte@Sun.COM };
58*7836SJohn.Forte@Sun.COM 
59*7836SJohn.Forte@Sun.COM /* standard subcommand options table to support -? */
60*7836SJohn.Forte@Sun.COM struct option standardSubCmdOptions[] = {
61*7836SJohn.Forte@Sun.COM 	{"help", no_argument, NULL, '?'},
62*7836SJohn.Forte@Sun.COM 	{NULL, 0, NULL, 0}
63*7836SJohn.Forte@Sun.COM };
64*7836SJohn.Forte@Sun.COM 
65*7836SJohn.Forte@Sun.COM /* forward declarations */
66*7836SJohn.Forte@Sun.COM static int getSubcommand(char *, subcommand_t **);
67*7836SJohn.Forte@Sun.COM static char *getExecBasename(char *);
68*7836SJohn.Forte@Sun.COM static void usage(uint_t);
69*7836SJohn.Forte@Sun.COM static void subUsage(uint_t, subcommand_t *);
70*7836SJohn.Forte@Sun.COM static void subUsageObject(uint_t, subcommand_t *, object_t *);
71*7836SJohn.Forte@Sun.COM static int getObject(char *, object_t **);
72*7836SJohn.Forte@Sun.COM static int getObjectRules(uint_t, objectRules_t **);
73*7836SJohn.Forte@Sun.COM static char *getLongOption(int);
74*7836SJohn.Forte@Sun.COM static optionProp_t *getOptions(uint_t, uint_t);
75*7836SJohn.Forte@Sun.COM static char *getOptionArgDesc(int);
76*7836SJohn.Forte@Sun.COM extern void seeMan(void);
77*7836SJohn.Forte@Sun.COM 
78*7836SJohn.Forte@Sun.COM /* global data */
79*7836SJohn.Forte@Sun.COM static struct option *_longOptions;
80*7836SJohn.Forte@Sun.COM static subcommand_t *_subcommands;
81*7836SJohn.Forte@Sun.COM static object_t *_objects;
82*7836SJohn.Forte@Sun.COM static objectRules_t *_objectRules;
83*7836SJohn.Forte@Sun.COM static optionRules_t *_optionRules;
84*7836SJohn.Forte@Sun.COM static optionTbl_t *_clientOptionTbl;
85*7836SJohn.Forte@Sun.COM static char *commandName;
86*7836SJohn.Forte@Sun.COM 
87*7836SJohn.Forte@Sun.COM 
88*7836SJohn.Forte@Sun.COM /*
89*7836SJohn.Forte@Sun.COM  * input:
90*7836SJohn.Forte@Sun.COM  *  object - object value
91*7836SJohn.Forte@Sun.COM  * output:
92*7836SJohn.Forte@Sun.COM  *  opCmd - pointer to opCmd_t structure allocated by caller
93*7836SJohn.Forte@Sun.COM  *
94*7836SJohn.Forte@Sun.COM  * On successful return, opCmd contains the rules for the value in
95*7836SJohn.Forte@Sun.COM  * object. On failure, the contents of opCmd is unspecified.
96*7836SJohn.Forte@Sun.COM  *
97*7836SJohn.Forte@Sun.COM  * Returns:
98*7836SJohn.Forte@Sun.COM  *  zero on success
99*7836SJohn.Forte@Sun.COM  *  non-zero on failure
100*7836SJohn.Forte@Sun.COM  *
101*7836SJohn.Forte@Sun.COM  */
102*7836SJohn.Forte@Sun.COM static int
getObjectRules(uint_t object,objectRules_t ** objectRules)103*7836SJohn.Forte@Sun.COM getObjectRules(uint_t object, objectRules_t **objectRules)
104*7836SJohn.Forte@Sun.COM {
105*7836SJohn.Forte@Sun.COM 	objectRules_t *sp;
106*7836SJohn.Forte@Sun.COM 
107*7836SJohn.Forte@Sun.COM 	for (sp = _objectRules; sp->value; sp++) {
108*7836SJohn.Forte@Sun.COM 		if (sp->value == object) {
109*7836SJohn.Forte@Sun.COM 			*objectRules = sp;
110*7836SJohn.Forte@Sun.COM 			return (0);
111*7836SJohn.Forte@Sun.COM 		}
112*7836SJohn.Forte@Sun.COM 	}
113*7836SJohn.Forte@Sun.COM 	return (1);
114*7836SJohn.Forte@Sun.COM }
115*7836SJohn.Forte@Sun.COM 
116*7836SJohn.Forte@Sun.COM /*
117*7836SJohn.Forte@Sun.COM  * input:
118*7836SJohn.Forte@Sun.COM  *  arg - pointer to array of char containing object string
119*7836SJohn.Forte@Sun.COM  *
120*7836SJohn.Forte@Sun.COM  * output:
121*7836SJohn.Forte@Sun.COM  *  object - pointer to object_t structure pointer
122*7836SJohn.Forte@Sun.COM  *	on success, contains the matching object structure based on
123*7836SJohn.Forte@Sun.COM  *	input object name
124*7836SJohn.Forte@Sun.COM  *
125*7836SJohn.Forte@Sun.COM  * Returns:
126*7836SJohn.Forte@Sun.COM  *  zero on success
127*7836SJohn.Forte@Sun.COM  *  non-zero otherwise
128*7836SJohn.Forte@Sun.COM  *
129*7836SJohn.Forte@Sun.COM  */
130*7836SJohn.Forte@Sun.COM static int
getObject(char * arg,object_t ** object)131*7836SJohn.Forte@Sun.COM getObject(char *arg, object_t **object)
132*7836SJohn.Forte@Sun.COM {
133*7836SJohn.Forte@Sun.COM 
134*7836SJohn.Forte@Sun.COM 	object_t *op;
135*7836SJohn.Forte@Sun.COM 	int len;
136*7836SJohn.Forte@Sun.COM 
137*7836SJohn.Forte@Sun.COM 	for (op = _objects; op->name; op++) {
138*7836SJohn.Forte@Sun.COM 		len = strlen(arg);
139*7836SJohn.Forte@Sun.COM 		if (len == strlen(op->name) &&
140*7836SJohn.Forte@Sun.COM 		    strncasecmp(arg, op->name, len) == 0) {
141*7836SJohn.Forte@Sun.COM 			*object = op;
142*7836SJohn.Forte@Sun.COM 			return (0);
143*7836SJohn.Forte@Sun.COM 		}
144*7836SJohn.Forte@Sun.COM 	}
145*7836SJohn.Forte@Sun.COM 	return (1);
146*7836SJohn.Forte@Sun.COM }
147*7836SJohn.Forte@Sun.COM 
148*7836SJohn.Forte@Sun.COM /*
149*7836SJohn.Forte@Sun.COM  * input:
150*7836SJohn.Forte@Sun.COM  *  arg - pointer to array of char containing subcommand string
151*7836SJohn.Forte@Sun.COM  * output:
152*7836SJohn.Forte@Sun.COM  *  subcommand - pointer to subcommand_t pointer
153*7836SJohn.Forte@Sun.COM  *	on success, contains the matching subcommand structure based on
154*7836SJohn.Forte@Sun.COM  *	input subcommand name
155*7836SJohn.Forte@Sun.COM  *
156*7836SJohn.Forte@Sun.COM  * Returns:
157*7836SJohn.Forte@Sun.COM  *  zero on success
158*7836SJohn.Forte@Sun.COM  *  non-zero on failure
159*7836SJohn.Forte@Sun.COM  */
160*7836SJohn.Forte@Sun.COM static int
getSubcommand(char * arg,subcommand_t ** subcommand)161*7836SJohn.Forte@Sun.COM getSubcommand(char *arg, subcommand_t **subcommand)
162*7836SJohn.Forte@Sun.COM {
163*7836SJohn.Forte@Sun.COM 	subcommand_t *sp;
164*7836SJohn.Forte@Sun.COM 	int len;
165*7836SJohn.Forte@Sun.COM 
166*7836SJohn.Forte@Sun.COM 	for (sp = _subcommands; sp->name; sp++) {
167*7836SJohn.Forte@Sun.COM 		len = strlen(arg);
168*7836SJohn.Forte@Sun.COM 		if (len == strlen(sp->name) &&
169*7836SJohn.Forte@Sun.COM 		    strncasecmp(arg, sp->name, len) == 0) {
170*7836SJohn.Forte@Sun.COM 			*subcommand = sp;
171*7836SJohn.Forte@Sun.COM 			return (0);
172*7836SJohn.Forte@Sun.COM 		}
173*7836SJohn.Forte@Sun.COM 	}
174*7836SJohn.Forte@Sun.COM 	return (1);
175*7836SJohn.Forte@Sun.COM }
176*7836SJohn.Forte@Sun.COM 
177*7836SJohn.Forte@Sun.COM /*
178*7836SJohn.Forte@Sun.COM  * input:
179*7836SJohn.Forte@Sun.COM  *  object - object for which to get options
180*7836SJohn.Forte@Sun.COM  *  subcommand - subcommand for which to get options
181*7836SJohn.Forte@Sun.COM  *
182*7836SJohn.Forte@Sun.COM  * Returns:
183*7836SJohn.Forte@Sun.COM  *  on success, optionsProp_t pointer to structure matching input object
184*7836SJohn.Forte@Sun.COM  *  value
185*7836SJohn.Forte@Sun.COM  *  on failure, NULL is returned
186*7836SJohn.Forte@Sun.COM  */
187*7836SJohn.Forte@Sun.COM static optionProp_t *
getOptions(uint_t object,uint_t subcommand)188*7836SJohn.Forte@Sun.COM getOptions(uint_t object, uint_t subcommand)
189*7836SJohn.Forte@Sun.COM {
190*7836SJohn.Forte@Sun.COM 	uint_t currObject;
191*7836SJohn.Forte@Sun.COM 	optionRules_t *op = _optionRules;
192*7836SJohn.Forte@Sun.COM 	while (op && ((currObject = op->objectValue) != 0)) {
193*7836SJohn.Forte@Sun.COM 		if ((currObject == object) &&
194*7836SJohn.Forte@Sun.COM 		    (op->subcommandValue == subcommand)) {
195*7836SJohn.Forte@Sun.COM 			return (&(op->optionProp));
196*7836SJohn.Forte@Sun.COM 		}
197*7836SJohn.Forte@Sun.COM 		op++;
198*7836SJohn.Forte@Sun.COM 	}
199*7836SJohn.Forte@Sun.COM 	return (NULL);
200*7836SJohn.Forte@Sun.COM }
201*7836SJohn.Forte@Sun.COM 
202*7836SJohn.Forte@Sun.COM /*
203*7836SJohn.Forte@Sun.COM  * input:
204*7836SJohn.Forte@Sun.COM  *  shortOption - short option character for which to return the
205*7836SJohn.Forte@Sun.COM  *	associated long option string
206*7836SJohn.Forte@Sun.COM  *
207*7836SJohn.Forte@Sun.COM  * Returns:
208*7836SJohn.Forte@Sun.COM  *  on success, long option name
209*7836SJohn.Forte@Sun.COM  *  on failure, NULL
210*7836SJohn.Forte@Sun.COM  */
211*7836SJohn.Forte@Sun.COM static char *
getLongOption(int shortOption)212*7836SJohn.Forte@Sun.COM getLongOption(int shortOption)
213*7836SJohn.Forte@Sun.COM {
214*7836SJohn.Forte@Sun.COM 	struct option *op;
215*7836SJohn.Forte@Sun.COM 	for (op = _longOptions; op->name; op++) {
216*7836SJohn.Forte@Sun.COM 		if (shortOption == op->val) {
217*7836SJohn.Forte@Sun.COM 			return (op->name);
218*7836SJohn.Forte@Sun.COM 		}
219*7836SJohn.Forte@Sun.COM 	}
220*7836SJohn.Forte@Sun.COM 	return (NULL);
221*7836SJohn.Forte@Sun.COM }
222*7836SJohn.Forte@Sun.COM 
223*7836SJohn.Forte@Sun.COM /*
224*7836SJohn.Forte@Sun.COM  * input
225*7836SJohn.Forte@Sun.COM  *  shortOption - short option character for which to return the
226*7836SJohn.Forte@Sun.COM  *	option argument
227*7836SJohn.Forte@Sun.COM  * Returns:
228*7836SJohn.Forte@Sun.COM  *  on success, argument string
229*7836SJohn.Forte@Sun.COM  *  on failure, NULL
230*7836SJohn.Forte@Sun.COM  */
231*7836SJohn.Forte@Sun.COM static char *
getOptionArgDesc(int shortOption)232*7836SJohn.Forte@Sun.COM getOptionArgDesc(int shortOption)
233*7836SJohn.Forte@Sun.COM {
234*7836SJohn.Forte@Sun.COM 	optionTbl_t *op;
235*7836SJohn.Forte@Sun.COM 	for (op = _clientOptionTbl; op->name; op++) {
236*7836SJohn.Forte@Sun.COM 		if (op->val == shortOption &&
237*7836SJohn.Forte@Sun.COM 		    op->has_arg == required_argument) {
238*7836SJohn.Forte@Sun.COM 			return (op->argDesc);
239*7836SJohn.Forte@Sun.COM 		}
240*7836SJohn.Forte@Sun.COM 	}
241*7836SJohn.Forte@Sun.COM 	return (NULL);
242*7836SJohn.Forte@Sun.COM }
243*7836SJohn.Forte@Sun.COM 
244*7836SJohn.Forte@Sun.COM 
245*7836SJohn.Forte@Sun.COM /*
246*7836SJohn.Forte@Sun.COM  * Print usage for a subcommand.
247*7836SJohn.Forte@Sun.COM  *
248*7836SJohn.Forte@Sun.COM  * input:
249*7836SJohn.Forte@Sun.COM  *  usage type - GENERAL_USAGE, HELP_USAGE, DETAIL_USAGE
250*7836SJohn.Forte@Sun.COM  *  subcommand - pointer to subcommand_t structure
251*7836SJohn.Forte@Sun.COM  *
252*7836SJohn.Forte@Sun.COM  * Returns:
253*7836SJohn.Forte@Sun.COM  *  none
254*7836SJohn.Forte@Sun.COM  *
255*7836SJohn.Forte@Sun.COM  */
256*7836SJohn.Forte@Sun.COM static void
subUsage(uint_t usageType,subcommand_t * subcommand)257*7836SJohn.Forte@Sun.COM subUsage(uint_t usageType, subcommand_t *subcommand)
258*7836SJohn.Forte@Sun.COM {
259*7836SJohn.Forte@Sun.COM 	int i;
260*7836SJohn.Forte@Sun.COM 	object_t *objp;
261*7836SJohn.Forte@Sun.COM 
262*7836SJohn.Forte@Sun.COM 
263*7836SJohn.Forte@Sun.COM 	(void) fprintf(stdout, "%s:\t%s %s [",
264*7836SJohn.Forte@Sun.COM 	    gettext("Usage"), commandName, subcommand->name);
265*7836SJohn.Forte@Sun.COM 
266*7836SJohn.Forte@Sun.COM 	for (i = 0; standardSubCmdOptions[i].name; i++) {
267*7836SJohn.Forte@Sun.COM 		(void) fprintf(stdout, "-%c",
268*7836SJohn.Forte@Sun.COM 		    standardSubCmdOptions[i].val);
269*7836SJohn.Forte@Sun.COM 		if (standardSubCmdOptions[i+1].name)
270*7836SJohn.Forte@Sun.COM 			(void) fprintf(stdout, ",");
271*7836SJohn.Forte@Sun.COM 	}
272*7836SJohn.Forte@Sun.COM 
273*7836SJohn.Forte@Sun.COM 	(void) fprintf(stdout, "] %s [", "<OBJECT>");
274*7836SJohn.Forte@Sun.COM 
275*7836SJohn.Forte@Sun.COM 	for (i = 0; standardSubCmdOptions[i].name; i++) {
276*7836SJohn.Forte@Sun.COM 		(void) fprintf(stdout, "-%c",
277*7836SJohn.Forte@Sun.COM 		    standardSubCmdOptions[i].val);
278*7836SJohn.Forte@Sun.COM 		if (standardSubCmdOptions[i+1].name)
279*7836SJohn.Forte@Sun.COM 			(void) fprintf(stdout, ",");
280*7836SJohn.Forte@Sun.COM 	}
281*7836SJohn.Forte@Sun.COM 
282*7836SJohn.Forte@Sun.COM 	(void) fprintf(stdout, "] %s", "[<OPERAND>]");
283*7836SJohn.Forte@Sun.COM 	(void) fprintf(stdout, "\n");
284*7836SJohn.Forte@Sun.COM 
285*7836SJohn.Forte@Sun.COM 	if (usageType == GENERAL_USAGE) {
286*7836SJohn.Forte@Sun.COM 		return;
287*7836SJohn.Forte@Sun.COM 	}
288*7836SJohn.Forte@Sun.COM 
289*7836SJohn.Forte@Sun.COM 	(void) fprintf(stdout, "%s:\n", gettext("Usage by OBJECT"));
290*7836SJohn.Forte@Sun.COM 
291*7836SJohn.Forte@Sun.COM 	/*
292*7836SJohn.Forte@Sun.COM 	 * iterate through object table
293*7836SJohn.Forte@Sun.COM 	 * For each object, print appropriate usage
294*7836SJohn.Forte@Sun.COM 	 * based on rules tables
295*7836SJohn.Forte@Sun.COM 	 */
296*7836SJohn.Forte@Sun.COM 	for (objp = _objects; objp->value; objp++) {
297*7836SJohn.Forte@Sun.COM 		subUsageObject(usageType, subcommand, objp);
298*7836SJohn.Forte@Sun.COM 	}
299*7836SJohn.Forte@Sun.COM 	(void) atexit(seeMan);
300*7836SJohn.Forte@Sun.COM }
301*7836SJohn.Forte@Sun.COM 
302*7836SJohn.Forte@Sun.COM /*
303*7836SJohn.Forte@Sun.COM  * Print usage for a subcommand and object.
304*7836SJohn.Forte@Sun.COM  *
305*7836SJohn.Forte@Sun.COM  * input:
306*7836SJohn.Forte@Sun.COM  *  usage type - GENERAL_USAGE, HELP_USAGE, DETAIL_USAGE
307*7836SJohn.Forte@Sun.COM  *  subcommand - pointer to subcommand_t structure
308*7836SJohn.Forte@Sun.COM  *  objp - pointer to a object_t structure
309*7836SJohn.Forte@Sun.COM  *
310*7836SJohn.Forte@Sun.COM  * Returns:
311*7836SJohn.Forte@Sun.COM  *  none
312*7836SJohn.Forte@Sun.COM  *
313*7836SJohn.Forte@Sun.COM  */
314*7836SJohn.Forte@Sun.COM static void
subUsageObject(uint_t usageType,subcommand_t * subcommand,object_t * objp)315*7836SJohn.Forte@Sun.COM subUsageObject(uint_t usageType, subcommand_t *subcommand, object_t *objp)
316*7836SJohn.Forte@Sun.COM {
317*7836SJohn.Forte@Sun.COM 	int i;
318*7836SJohn.Forte@Sun.COM 	objectRules_t *objRules = NULL;
319*7836SJohn.Forte@Sun.COM 	opCmd_t *opCmd = NULL;
320*7836SJohn.Forte@Sun.COM 	optionProp_t *options;
321*7836SJohn.Forte@Sun.COM 	char *optionArgDesc;
322*7836SJohn.Forte@Sun.COM 	char *longOpt;
323*7836SJohn.Forte@Sun.COM 
324*7836SJohn.Forte@Sun.COM 
325*7836SJohn.Forte@Sun.COM 	if (getObjectRules(objp->value, &objRules) != 0) {
326*7836SJohn.Forte@Sun.COM 		/*
327*7836SJohn.Forte@Sun.COM 		 * internal subcommand rules table error
328*7836SJohn.Forte@Sun.COM 		 * no object entry in object
329*7836SJohn.Forte@Sun.COM 		 */
330*7836SJohn.Forte@Sun.COM 		assert(0);
331*7836SJohn.Forte@Sun.COM 	}
332*7836SJohn.Forte@Sun.COM 
333*7836SJohn.Forte@Sun.COM 	opCmd = &(objRules->opCmd);
334*7836SJohn.Forte@Sun.COM 
335*7836SJohn.Forte@Sun.COM 	if (opCmd->invOpCmd & subcommand->value) {
336*7836SJohn.Forte@Sun.COM 		return;
337*7836SJohn.Forte@Sun.COM 	}
338*7836SJohn.Forte@Sun.COM 
339*7836SJohn.Forte@Sun.COM 	options = getOptions(objp->value, subcommand->value);
340*7836SJohn.Forte@Sun.COM 
341*7836SJohn.Forte@Sun.COM 	/* print generic subcommand usage */
342*7836SJohn.Forte@Sun.COM 	(void) fprintf(stdout, "\t%s %s ", commandName, subcommand->name);
343*7836SJohn.Forte@Sun.COM 
344*7836SJohn.Forte@Sun.COM 	/* print object */
345*7836SJohn.Forte@Sun.COM 	(void) fprintf(stdout, "%s ", objp->name);
346*7836SJohn.Forte@Sun.COM 
347*7836SJohn.Forte@Sun.COM 	/* print options if applicable */
348*7836SJohn.Forte@Sun.COM 	if (options != NULL) {
349*7836SJohn.Forte@Sun.COM 		if (options->required) {
350*7836SJohn.Forte@Sun.COM 			(void) fprintf(stdout, "%s", gettext("<"));
351*7836SJohn.Forte@Sun.COM 		} else {
352*7836SJohn.Forte@Sun.COM 			(void) fprintf(stdout, "%s", gettext("["));
353*7836SJohn.Forte@Sun.COM 		}
354*7836SJohn.Forte@Sun.COM 		(void) fprintf(stdout, "%s", gettext("OPTIONS"));
355*7836SJohn.Forte@Sun.COM 		if (options->required) {
356*7836SJohn.Forte@Sun.COM 			(void) fprintf(stdout, "%s ", gettext(">"));
357*7836SJohn.Forte@Sun.COM 		} else {
358*7836SJohn.Forte@Sun.COM 			(void) fprintf(stdout, "%s ", gettext("]"));
359*7836SJohn.Forte@Sun.COM 		}
360*7836SJohn.Forte@Sun.COM 	}
361*7836SJohn.Forte@Sun.COM 
362*7836SJohn.Forte@Sun.COM 	/* print operand requirements */
363*7836SJohn.Forte@Sun.COM 	if (opCmd->optOpCmd & subcommand->value) {
364*7836SJohn.Forte@Sun.COM 		(void) fprintf(stdout, gettext("["));
365*7836SJohn.Forte@Sun.COM 	}
366*7836SJohn.Forte@Sun.COM 	if (!(opCmd->noOpCmd & subcommand->value)) {
367*7836SJohn.Forte@Sun.COM 		(void) fprintf(stdout, gettext("<"));
368*7836SJohn.Forte@Sun.COM 		if (objRules->operandDefinition) {
369*7836SJohn.Forte@Sun.COM 			(void) fprintf(stdout, "%s",
370*7836SJohn.Forte@Sun.COM 			    objRules->operandDefinition);
371*7836SJohn.Forte@Sun.COM 		} else {
372*7836SJohn.Forte@Sun.COM 			/*
373*7836SJohn.Forte@Sun.COM 			 * Missing operand description
374*7836SJohn.Forte@Sun.COM 			 * from table
375*7836SJohn.Forte@Sun.COM 			 */
376*7836SJohn.Forte@Sun.COM 			assert(0);
377*7836SJohn.Forte@Sun.COM 		}
378*7836SJohn.Forte@Sun.COM 	}
379*7836SJohn.Forte@Sun.COM 	if (opCmd->multOpCmd & subcommand->value) {
380*7836SJohn.Forte@Sun.COM 		(void) fprintf(stdout, gettext(" ..."));
381*7836SJohn.Forte@Sun.COM 	}
382*7836SJohn.Forte@Sun.COM 	if (!(opCmd->noOpCmd & subcommand->value)) {
383*7836SJohn.Forte@Sun.COM 		(void) fprintf(stdout, gettext(">"));
384*7836SJohn.Forte@Sun.COM 	}
385*7836SJohn.Forte@Sun.COM 	if (opCmd->optOpCmd & subcommand->value) {
386*7836SJohn.Forte@Sun.COM 		(void) fprintf(stdout, gettext("]"));
387*7836SJohn.Forte@Sun.COM 	}
388*7836SJohn.Forte@Sun.COM 
389*7836SJohn.Forte@Sun.COM 	if (usageType == HELP_USAGE) {
390*7836SJohn.Forte@Sun.COM 		(void) fprintf(stdout, "\n");
391*7836SJohn.Forte@Sun.COM 		return;
392*7836SJohn.Forte@Sun.COM 	}
393*7836SJohn.Forte@Sun.COM 
394*7836SJohn.Forte@Sun.COM 	/* print options for subcommand, object */
395*7836SJohn.Forte@Sun.COM 	if (options != NULL && options->optionString != NULL) {
396*7836SJohn.Forte@Sun.COM 		(void) fprintf(stdout, "\n\t%s:", gettext("OPTIONS"));
397*7836SJohn.Forte@Sun.COM 		for (i = 0; i < strlen(options->optionString); i++) {
398*7836SJohn.Forte@Sun.COM 			if ((longOpt = getLongOption(
399*7836SJohn.Forte@Sun.COM 			    options->optionString[i]))
400*7836SJohn.Forte@Sun.COM 			    == NULL) {
401*7836SJohn.Forte@Sun.COM 				/* no long option exists for short option */
402*7836SJohn.Forte@Sun.COM 				assert(0);
403*7836SJohn.Forte@Sun.COM 			}
404*7836SJohn.Forte@Sun.COM 			(void) fprintf(stdout, "\n\t\t-%c, --%s  ",
405*7836SJohn.Forte@Sun.COM 			    options->optionString[i], longOpt);
406*7836SJohn.Forte@Sun.COM 			optionArgDesc =
407*7836SJohn.Forte@Sun.COM 			    getOptionArgDesc(options->optionString[i]);
408*7836SJohn.Forte@Sun.COM 			if (optionArgDesc != NULL) {
409*7836SJohn.Forte@Sun.COM 				(void) fprintf(stdout, "<%s>", optionArgDesc);
410*7836SJohn.Forte@Sun.COM 			}
411*7836SJohn.Forte@Sun.COM 			if (options->exclusive &&
412*7836SJohn.Forte@Sun.COM 			    strchr(options->exclusive,
413*7836SJohn.Forte@Sun.COM 			    options->optionString[i])) {
414*7836SJohn.Forte@Sun.COM 				(void) fprintf(stdout, " (%s)",
415*7836SJohn.Forte@Sun.COM 				gettext("exclusive"));
416*7836SJohn.Forte@Sun.COM 			}
417*7836SJohn.Forte@Sun.COM 		}
418*7836SJohn.Forte@Sun.COM 	}
419*7836SJohn.Forte@Sun.COM 	(void) fprintf(stdout, "\n");
420*7836SJohn.Forte@Sun.COM 	(void) atexit(seeMan);
421*7836SJohn.Forte@Sun.COM }
422*7836SJohn.Forte@Sun.COM 
423*7836SJohn.Forte@Sun.COM /*
424*7836SJohn.Forte@Sun.COM  * input:
425*7836SJohn.Forte@Sun.COM  *  type of usage statement to print
426*7836SJohn.Forte@Sun.COM  *
427*7836SJohn.Forte@Sun.COM  * Returns:
428*7836SJohn.Forte@Sun.COM  *  return value of subUsage
429*7836SJohn.Forte@Sun.COM  */
430*7836SJohn.Forte@Sun.COM static void
usage(uint_t usageType)431*7836SJohn.Forte@Sun.COM usage(uint_t usageType)
432*7836SJohn.Forte@Sun.COM {
433*7836SJohn.Forte@Sun.COM 	int i;
434*7836SJohn.Forte@Sun.COM 	subcommand_t subcommand;
435*7836SJohn.Forte@Sun.COM 	subcommand_t *sp;
436*7836SJohn.Forte@Sun.COM 
437*7836SJohn.Forte@Sun.COM 	/* print general command usage */
438*7836SJohn.Forte@Sun.COM 	(void) fprintf(stdout, "%s:\t%s ",
439*7836SJohn.Forte@Sun.COM 	    gettext("Usage"), commandName);
440*7836SJohn.Forte@Sun.COM 
441*7836SJohn.Forte@Sun.COM 	for (i = 0; standardCmdOptions[i].name; i++) {
442*7836SJohn.Forte@Sun.COM 		(void) fprintf(stdout, "-%c",
443*7836SJohn.Forte@Sun.COM 		    standardCmdOptions[i].val);
444*7836SJohn.Forte@Sun.COM 		if (standardCmdOptions[i+1].name)
445*7836SJohn.Forte@Sun.COM 			(void) fprintf(stdout, ",");
446*7836SJohn.Forte@Sun.COM 	}
447*7836SJohn.Forte@Sun.COM 
448*7836SJohn.Forte@Sun.COM 	if (usageType == HELP_USAGE || usageType == GENERAL_USAGE) {
449*7836SJohn.Forte@Sun.COM 		for (i = 0; standardCmdOptions[i].name; i++) {
450*7836SJohn.Forte@Sun.COM 
451*7836SJohn.Forte@Sun.COM 
452*7836SJohn.Forte@Sun.COM 		}
453*7836SJohn.Forte@Sun.COM 	}
454*7836SJohn.Forte@Sun.COM 
455*7836SJohn.Forte@Sun.COM 	(void) fprintf(stdout, "\n");
456*7836SJohn.Forte@Sun.COM 
457*7836SJohn.Forte@Sun.COM 
458*7836SJohn.Forte@Sun.COM 	/* print all subcommand usage */
459*7836SJohn.Forte@Sun.COM 	for (sp = _subcommands; sp->name; sp++) {
460*7836SJohn.Forte@Sun.COM 		subcommand.name = sp->name;
461*7836SJohn.Forte@Sun.COM 		subcommand.value = sp->value;
462*7836SJohn.Forte@Sun.COM 		if (usageType == HELP_USAGE) {
463*7836SJohn.Forte@Sun.COM 			(void) fprintf(stdout, "\n");
464*7836SJohn.Forte@Sun.COM 		}
465*7836SJohn.Forte@Sun.COM 		subUsage(usageType, &subcommand);
466*7836SJohn.Forte@Sun.COM 	}
467*7836SJohn.Forte@Sun.COM 	(void) atexit(seeMan);
468*7836SJohn.Forte@Sun.COM }
469*7836SJohn.Forte@Sun.COM 
470*7836SJohn.Forte@Sun.COM /*
471*7836SJohn.Forte@Sun.COM  * input:
472*7836SJohn.Forte@Sun.COM  *  execFullName - exec name of program (argv[0])
473*7836SJohn.Forte@Sun.COM  *
474*7836SJohn.Forte@Sun.COM  * Returns:
475*7836SJohn.Forte@Sun.COM  *  command name portion of execFullName
476*7836SJohn.Forte@Sun.COM  */
477*7836SJohn.Forte@Sun.COM static char *
getExecBasename(char * execFullname)478*7836SJohn.Forte@Sun.COM getExecBasename(char *execFullname)
479*7836SJohn.Forte@Sun.COM {
480*7836SJohn.Forte@Sun.COM 	char *lastSlash, *execBasename;
481*7836SJohn.Forte@Sun.COM 
482*7836SJohn.Forte@Sun.COM 	/* guard against '/' at end of command invocation */
483*7836SJohn.Forte@Sun.COM 	for (;;) {
484*7836SJohn.Forte@Sun.COM 		lastSlash = strrchr(execFullname, '/');
485*7836SJohn.Forte@Sun.COM 		if (lastSlash == NULL) {
486*7836SJohn.Forte@Sun.COM 			execBasename = execFullname;
487*7836SJohn.Forte@Sun.COM 			break;
488*7836SJohn.Forte@Sun.COM 		} else {
489*7836SJohn.Forte@Sun.COM 			execBasename = lastSlash + 1;
490*7836SJohn.Forte@Sun.COM 			if (*execBasename == '\0') {
491*7836SJohn.Forte@Sun.COM 				*lastSlash = '\0';
492*7836SJohn.Forte@Sun.COM 				continue;
493*7836SJohn.Forte@Sun.COM 			}
494*7836SJohn.Forte@Sun.COM 			break;
495*7836SJohn.Forte@Sun.COM 		}
496*7836SJohn.Forte@Sun.COM 	}
497*7836SJohn.Forte@Sun.COM 	return (execBasename);
498*7836SJohn.Forte@Sun.COM }
499*7836SJohn.Forte@Sun.COM 
500*7836SJohn.Forte@Sun.COM /*
501*7836SJohn.Forte@Sun.COM  * cmdParse is a parser that checks syntax of the input command against
502*7836SJohn.Forte@Sun.COM  * various rules tables.
503*7836SJohn.Forte@Sun.COM  *
504*7836SJohn.Forte@Sun.COM  * It provides usage feedback based upon the passed rules tables by calling
505*7836SJohn.Forte@Sun.COM  * two usage functions, usage, subUsage, and subUsageObject handling command,
506*7836SJohn.Forte@Sun.COM  * subcommand and object usage respectively.
507*7836SJohn.Forte@Sun.COM  *
508*7836SJohn.Forte@Sun.COM  * When syntax is successfully validated, the associated function is called
509*7836SJohn.Forte@Sun.COM  * using the subcommands table functions.
510*7836SJohn.Forte@Sun.COM  *
511*7836SJohn.Forte@Sun.COM  * Syntax is as follows:
512*7836SJohn.Forte@Sun.COM  *	command subcommand object [<options>] [<operand>]
513*7836SJohn.Forte@Sun.COM  *
514*7836SJohn.Forte@Sun.COM  * There are two standard short and long options assumed:
515*7836SJohn.Forte@Sun.COM  *	-?, --help	Provides usage on a command or subcommand
516*7836SJohn.Forte@Sun.COM  *			and stops further processing of the arguments
517*7836SJohn.Forte@Sun.COM  *
518*7836SJohn.Forte@Sun.COM  *	-V, --version	Provides version information on the command
519*7836SJohn.Forte@Sun.COM  *			and stops further processing of the arguments
520*7836SJohn.Forte@Sun.COM  *
521*7836SJohn.Forte@Sun.COM  *	These options are loaded by this function.
522*7836SJohn.Forte@Sun.COM  *
523*7836SJohn.Forte@Sun.COM  * input:
524*7836SJohn.Forte@Sun.COM  *  argc, argv from main
525*7836SJohn.Forte@Sun.COM  *  syntax rules tables (synTables_t structure)
526*7836SJohn.Forte@Sun.COM  *  callArgs - void * passed by caller to be passed to subcommand function
527*7836SJohn.Forte@Sun.COM  *
528*7836SJohn.Forte@Sun.COM  * output:
529*7836SJohn.Forte@Sun.COM  *  funcRet - pointer to int that holds subcommand function return value
530*7836SJohn.Forte@Sun.COM  *
531*7836SJohn.Forte@Sun.COM  * Returns:
532*7836SJohn.Forte@Sun.COM  *
533*7836SJohn.Forte@Sun.COM  *     zero on successful syntax parse and function call
534*7836SJohn.Forte@Sun.COM  *
535*7836SJohn.Forte@Sun.COM  *     1 on unsuccessful syntax parse (no function has been called)
536*7836SJohn.Forte@Sun.COM  *		This could be due to a version or help call or simply a
537*7836SJohn.Forte@Sun.COM  *		general usage call.
538*7836SJohn.Forte@Sun.COM  *
539*7836SJohn.Forte@Sun.COM  *     -1 check errno, call failed
540*7836SJohn.Forte@Sun.COM  *
541*7836SJohn.Forte@Sun.COM  *  This module is not MT-safe.
542*7836SJohn.Forte@Sun.COM  *
543*7836SJohn.Forte@Sun.COM  */
544*7836SJohn.Forte@Sun.COM int
cmdParse(int argc,char * argv[],synTables_t synTable,void * callArgs,int * funcRet)545*7836SJohn.Forte@Sun.COM cmdParse(int argc, char *argv[], synTables_t synTable, void *callArgs,
546*7836SJohn.Forte@Sun.COM     int *funcRet)
547*7836SJohn.Forte@Sun.COM {
548*7836SJohn.Forte@Sun.COM 	int	getoptargc;
549*7836SJohn.Forte@Sun.COM 	char	**getoptargv;
550*7836SJohn.Forte@Sun.COM 	int	opt;
551*7836SJohn.Forte@Sun.COM 	int	operInd;
552*7836SJohn.Forte@Sun.COM 	int	i, j;
553*7836SJohn.Forte@Sun.COM 	int	len;
554*7836SJohn.Forte@Sun.COM 	char	*versionString;
555*7836SJohn.Forte@Sun.COM 	char	optionStringAll[MAXOPTIONSTRING + 1];
556*7836SJohn.Forte@Sun.COM 	optionProp_t	*availOptions;
557*7836SJohn.Forte@Sun.COM 	objectRules_t *objRules = NULL;
558*7836SJohn.Forte@Sun.COM 	opCmd_t *opCmd = NULL;
559*7836SJohn.Forte@Sun.COM 	subcommand_t *subcommand;
560*7836SJohn.Forte@Sun.COM 	object_t *object;
561*7836SJohn.Forte@Sun.COM 	cmdOptions_t cmdOptions[MAXOPTIONS + 1];
562*7836SJohn.Forte@Sun.COM 	struct option *lp;
563*7836SJohn.Forte@Sun.COM 	optionTbl_t *optionTbl;
564*7836SJohn.Forte@Sun.COM 	struct option intLongOpt[MAXOPTIONS + 1];
565*7836SJohn.Forte@Sun.COM 
566*7836SJohn.Forte@Sun.COM 	/*
567*7836SJohn.Forte@Sun.COM 	 * Check for NULLs on mandatory input arguments
568*7836SJohn.Forte@Sun.COM 	 *
569*7836SJohn.Forte@Sun.COM 	 * Note: longOptionTbl and optionRulesTbl can be NULL in the case
570*7836SJohn.Forte@Sun.COM 	 * where there is no caller defined options
571*7836SJohn.Forte@Sun.COM 	 *
572*7836SJohn.Forte@Sun.COM 	 */
573*7836SJohn.Forte@Sun.COM 	if (synTable.versionString == NULL ||
574*7836SJohn.Forte@Sun.COM 	    synTable.subcommandTbl == NULL ||
575*7836SJohn.Forte@Sun.COM 	    synTable.objectRulesTbl == NULL ||
576*7836SJohn.Forte@Sun.COM 	    synTable.objectTbl == NULL ||
577*7836SJohn.Forte@Sun.COM 	    funcRet == NULL) {
578*7836SJohn.Forte@Sun.COM 		assert(0);
579*7836SJohn.Forte@Sun.COM 	}
580*7836SJohn.Forte@Sun.COM 
581*7836SJohn.Forte@Sun.COM 
582*7836SJohn.Forte@Sun.COM 	versionString = synTable.versionString;
583*7836SJohn.Forte@Sun.COM 
584*7836SJohn.Forte@Sun.COM 	/* set global command name */
585*7836SJohn.Forte@Sun.COM 	commandName = getExecBasename(argv[0]);
586*7836SJohn.Forte@Sun.COM 
587*7836SJohn.Forte@Sun.COM 	/* Set unbuffered output */
588*7836SJohn.Forte@Sun.COM 	setbuf(stdout, NULL);
589*7836SJohn.Forte@Sun.COM 
590*7836SJohn.Forte@Sun.COM 	/* load globals */
591*7836SJohn.Forte@Sun.COM 	_subcommands = synTable.subcommandTbl;
592*7836SJohn.Forte@Sun.COM 	_objectRules = synTable.objectRulesTbl;
593*7836SJohn.Forte@Sun.COM 	_optionRules = synTable.optionRulesTbl;
594*7836SJohn.Forte@Sun.COM 	_objects = synTable.objectTbl;
595*7836SJohn.Forte@Sun.COM 	_clientOptionTbl = synTable.longOptionTbl;
596*7836SJohn.Forte@Sun.COM 
597*7836SJohn.Forte@Sun.COM 	/* There must be at least two arguments */
598*7836SJohn.Forte@Sun.COM 	if (argc < 2) {
599*7836SJohn.Forte@Sun.COM 		usage(GENERAL_USAGE);
600*7836SJohn.Forte@Sun.COM 		return (1);
601*7836SJohn.Forte@Sun.COM 	}
602*7836SJohn.Forte@Sun.COM 
603*7836SJohn.Forte@Sun.COM 	(void) memset(&intLongOpt[0], 0, sizeof (intLongOpt));
604*7836SJohn.Forte@Sun.COM 
605*7836SJohn.Forte@Sun.COM 	/*
606*7836SJohn.Forte@Sun.COM 	 * load standard subcommand options to internal long options table
607*7836SJohn.Forte@Sun.COM 	 * Two separate getopt_long(3C) tables are used.
608*7836SJohn.Forte@Sun.COM 	 */
609*7836SJohn.Forte@Sun.COM 	for (i = 0; standardSubCmdOptions[i].name; i++) {
610*7836SJohn.Forte@Sun.COM 		intLongOpt[i].name = standardSubCmdOptions[i].name;
611*7836SJohn.Forte@Sun.COM 		intLongOpt[i].has_arg = standardSubCmdOptions[i].has_arg;
612*7836SJohn.Forte@Sun.COM 		intLongOpt[i].flag = standardSubCmdOptions[i].flag;
613*7836SJohn.Forte@Sun.COM 		intLongOpt[i].val = standardSubCmdOptions[i].val;
614*7836SJohn.Forte@Sun.COM 	}
615*7836SJohn.Forte@Sun.COM 
616*7836SJohn.Forte@Sun.COM 	/*
617*7836SJohn.Forte@Sun.COM 	 * copy caller's long options into internal long options table
618*7836SJohn.Forte@Sun.COM 	 * We do this for two reasons:
619*7836SJohn.Forte@Sun.COM 	 *  1) We need to use the getopt_long option structure internally
620*7836SJohn.Forte@Sun.COM 	 *  2) We need to prepend the table with the standard option
621*7836SJohn.Forte@Sun.COM 	 *	for all subcommands (currently -?)
622*7836SJohn.Forte@Sun.COM 	 */
623*7836SJohn.Forte@Sun.COM 	for (optionTbl = synTable.longOptionTbl;
624*7836SJohn.Forte@Sun.COM 	    optionTbl && optionTbl->name; optionTbl++, i++) {
625*7836SJohn.Forte@Sun.COM 		if (i > MAXOPTIONS - 1) {
626*7836SJohn.Forte@Sun.COM 			/* option table too long */
627*7836SJohn.Forte@Sun.COM 			assert(0);
628*7836SJohn.Forte@Sun.COM 		}
629*7836SJohn.Forte@Sun.COM 		intLongOpt[i].name = optionTbl->name;
630*7836SJohn.Forte@Sun.COM 		intLongOpt[i].has_arg = optionTbl->has_arg;
631*7836SJohn.Forte@Sun.COM 		intLongOpt[i].flag = NULL;
632*7836SJohn.Forte@Sun.COM 		intLongOpt[i].val = optionTbl->val;
633*7836SJohn.Forte@Sun.COM 	}
634*7836SJohn.Forte@Sun.COM 
635*7836SJohn.Forte@Sun.COM 	/* set option table global */
636*7836SJohn.Forte@Sun.COM 	_longOptions = &intLongOpt[0];
637*7836SJohn.Forte@Sun.COM 
638*7836SJohn.Forte@Sun.COM 
639*7836SJohn.Forte@Sun.COM 	/*
640*7836SJohn.Forte@Sun.COM 	 * Check for help/version request immediately following command
641*7836SJohn.Forte@Sun.COM 	 * '+' in option string ensures POSIX compliance in getopt_long()
642*7836SJohn.Forte@Sun.COM 	 * which means that processing will stop at first non-option
643*7836SJohn.Forte@Sun.COM 	 * argument.
644*7836SJohn.Forte@Sun.COM 	 */
645*7836SJohn.Forte@Sun.COM 	while ((opt = getopt_long(argc, argv, "+?V", standardCmdOptions,
646*7836SJohn.Forte@Sun.COM 	    NULL)) != EOF) {
647*7836SJohn.Forte@Sun.COM 		switch (opt) {
648*7836SJohn.Forte@Sun.COM 			case '?':
649*7836SJohn.Forte@Sun.COM 				/*
650*7836SJohn.Forte@Sun.COM 				 * getopt can return a '?' when no
651*7836SJohn.Forte@Sun.COM 				 * option letters match string. Check for
652*7836SJohn.Forte@Sun.COM 				 * the 'real' '?' in optopt.
653*7836SJohn.Forte@Sun.COM 				 */
654*7836SJohn.Forte@Sun.COM 				if (optopt == '?') {
655*7836SJohn.Forte@Sun.COM 					usage(HELP_USAGE);
656*7836SJohn.Forte@Sun.COM 					return (0);
657*7836SJohn.Forte@Sun.COM 				} else {
658*7836SJohn.Forte@Sun.COM 					usage(GENERAL_USAGE);
659*7836SJohn.Forte@Sun.COM 					return (0);
660*7836SJohn.Forte@Sun.COM 				}
661*7836SJohn.Forte@Sun.COM 			case 'V':
662*7836SJohn.Forte@Sun.COM 				(void) fprintf(stdout, "%s: %s %s\n",
663*7836SJohn.Forte@Sun.COM 				    commandName, gettext("Version"),
664*7836SJohn.Forte@Sun.COM 				    versionString);
665*7836SJohn.Forte@Sun.COM 				(void) atexit(seeMan);
666*7836SJohn.Forte@Sun.COM 				return (0);
667*7836SJohn.Forte@Sun.COM 			default:
668*7836SJohn.Forte@Sun.COM 				break;
669*7836SJohn.Forte@Sun.COM 		}
670*7836SJohn.Forte@Sun.COM 	}
671*7836SJohn.Forte@Sun.COM 
672*7836SJohn.Forte@Sun.COM 	/*
673*7836SJohn.Forte@Sun.COM 	 * subcommand is always in the second argument. If there is no
674*7836SJohn.Forte@Sun.COM 	 * recognized subcommand in the second argument, print error,
675*7836SJohn.Forte@Sun.COM 	 * general usage and then return.
676*7836SJohn.Forte@Sun.COM 	 */
677*7836SJohn.Forte@Sun.COM 	if (getSubcommand(argv[1], &subcommand) != 0) {
678*7836SJohn.Forte@Sun.COM 		(void) fprintf(stderr, "%s: %s\n",
679*7836SJohn.Forte@Sun.COM 		    commandName, gettext("invalid subcommand"));
680*7836SJohn.Forte@Sun.COM 		usage(GENERAL_USAGE);
681*7836SJohn.Forte@Sun.COM 		return (1);
682*7836SJohn.Forte@Sun.COM 	}
683*7836SJohn.Forte@Sun.COM 
684*7836SJohn.Forte@Sun.COM 	if (argc == 2) {
685*7836SJohn.Forte@Sun.COM 		(void) fprintf(stderr, "%s: %s\n",
686*7836SJohn.Forte@Sun.COM 		    commandName, gettext("missing object"));
687*7836SJohn.Forte@Sun.COM 		subUsage(GENERAL_USAGE, subcommand);
688*7836SJohn.Forte@Sun.COM 		(void) atexit(seeMan);
689*7836SJohn.Forte@Sun.COM 		return (1);
690*7836SJohn.Forte@Sun.COM 	}
691*7836SJohn.Forte@Sun.COM 
692*7836SJohn.Forte@Sun.COM 	getoptargv = argv;
693*7836SJohn.Forte@Sun.COM 	getoptargv++;
694*7836SJohn.Forte@Sun.COM 	getoptargc = argc;
695*7836SJohn.Forte@Sun.COM 	getoptargc -= 1;
696*7836SJohn.Forte@Sun.COM 
697*7836SJohn.Forte@Sun.COM 	while ((opt = getopt_long(getoptargc, getoptargv, "+?",
698*7836SJohn.Forte@Sun.COM 	    standardSubCmdOptions, NULL)) != EOF) {
699*7836SJohn.Forte@Sun.COM 		switch (opt) {
700*7836SJohn.Forte@Sun.COM 			case '?':
701*7836SJohn.Forte@Sun.COM 				/*
702*7836SJohn.Forte@Sun.COM 				 * getopt can return a '?' when no
703*7836SJohn.Forte@Sun.COM 				 * option letters match string. Check for
704*7836SJohn.Forte@Sun.COM 				 * the 'real' '?' in optopt.
705*7836SJohn.Forte@Sun.COM 				 */
706*7836SJohn.Forte@Sun.COM 				if (optopt == '?') {
707*7836SJohn.Forte@Sun.COM 					subUsage(HELP_USAGE, subcommand);
708*7836SJohn.Forte@Sun.COM 					return (0);
709*7836SJohn.Forte@Sun.COM 				} else {
710*7836SJohn.Forte@Sun.COM 					subUsage(GENERAL_USAGE, subcommand);
711*7836SJohn.Forte@Sun.COM 					return (0);
712*7836SJohn.Forte@Sun.COM 				}
713*7836SJohn.Forte@Sun.COM 			default:
714*7836SJohn.Forte@Sun.COM 				break;
715*7836SJohn.Forte@Sun.COM 		}
716*7836SJohn.Forte@Sun.COM 	}
717*7836SJohn.Forte@Sun.COM 
718*7836SJohn.Forte@Sun.COM 
719*7836SJohn.Forte@Sun.COM 	/*
720*7836SJohn.Forte@Sun.COM 	 * object is always in the third argument. If there is no
721*7836SJohn.Forte@Sun.COM 	 * recognized object in the third argument, print error,
722*7836SJohn.Forte@Sun.COM 	 * help usage for the subcommand and then return.
723*7836SJohn.Forte@Sun.COM 	 */
724*7836SJohn.Forte@Sun.COM 	if (getObject(argv[2], &object) != 0) {
725*7836SJohn.Forte@Sun.COM 		(void) fprintf(stderr, "%s: %s\n",
726*7836SJohn.Forte@Sun.COM 		    commandName, gettext("invalid object"));
727*7836SJohn.Forte@Sun.COM 		subUsage(HELP_USAGE, subcommand);
728*7836SJohn.Forte@Sun.COM 		return (1);
729*7836SJohn.Forte@Sun.COM 
730*7836SJohn.Forte@Sun.COM 	}
731*7836SJohn.Forte@Sun.COM 
732*7836SJohn.Forte@Sun.COM 	if (getObjectRules(object->value, &objRules) != 0) {
733*7836SJohn.Forte@Sun.COM 		/*
734*7836SJohn.Forte@Sun.COM 		 * internal subcommand rules table error
735*7836SJohn.Forte@Sun.COM 		 * no object entry in object table
736*7836SJohn.Forte@Sun.COM 		 */
737*7836SJohn.Forte@Sun.COM 		assert(0);
738*7836SJohn.Forte@Sun.COM 	}
739*7836SJohn.Forte@Sun.COM 
740*7836SJohn.Forte@Sun.COM 	opCmd = &(objRules->opCmd);
741*7836SJohn.Forte@Sun.COM 
742*7836SJohn.Forte@Sun.COM 	/*
743*7836SJohn.Forte@Sun.COM 	 * Is command valid for this object?
744*7836SJohn.Forte@Sun.COM 	 */
745*7836SJohn.Forte@Sun.COM 	if (opCmd->invOpCmd & subcommand->value) {
746*7836SJohn.Forte@Sun.COM 		(void) fprintf(stderr, "%s: %s %s\n", commandName,
747*7836SJohn.Forte@Sun.COM 		    gettext("invalid subcommand for"), object->name);
748*7836SJohn.Forte@Sun.COM 		subUsage(HELP_USAGE, subcommand);
749*7836SJohn.Forte@Sun.COM 		return (1);
750*7836SJohn.Forte@Sun.COM 	}
751*7836SJohn.Forte@Sun.COM 
752*7836SJohn.Forte@Sun.COM 	/*
753*7836SJohn.Forte@Sun.COM 	 * offset getopt arg begin since
754*7836SJohn.Forte@Sun.COM 	 * getopt(3C) assumes options
755*7836SJohn.Forte@Sun.COM 	 * follow first argument
756*7836SJohn.Forte@Sun.COM 	 */
757*7836SJohn.Forte@Sun.COM 	getoptargv = argv;
758*7836SJohn.Forte@Sun.COM 	getoptargv++;
759*7836SJohn.Forte@Sun.COM 	getoptargv++;
760*7836SJohn.Forte@Sun.COM 	getoptargc = argc;
761*7836SJohn.Forte@Sun.COM 	getoptargc -= 2;
762*7836SJohn.Forte@Sun.COM 
763*7836SJohn.Forte@Sun.COM 	(void) memset(optionStringAll, 0, sizeof (optionStringAll));
764*7836SJohn.Forte@Sun.COM 	(void) memset(&cmdOptions[0], 0, sizeof (cmdOptions));
765*7836SJohn.Forte@Sun.COM 
766*7836SJohn.Forte@Sun.COM 	j = 0;
767*7836SJohn.Forte@Sun.COM 	/*
768*7836SJohn.Forte@Sun.COM 	 * Build optionStringAll from long options table
769*7836SJohn.Forte@Sun.COM 	 */
770*7836SJohn.Forte@Sun.COM 	for (lp = _longOptions;  lp->name; lp++, j++) {
771*7836SJohn.Forte@Sun.COM 		/* sanity check on string length */
772*7836SJohn.Forte@Sun.COM 		if (j + 1 >= sizeof (optionStringAll)) {
773*7836SJohn.Forte@Sun.COM 			/* option table too long */
774*7836SJohn.Forte@Sun.COM 			assert(0);
775*7836SJohn.Forte@Sun.COM 		}
776*7836SJohn.Forte@Sun.COM 		optionStringAll[j] = lp->val;
777*7836SJohn.Forte@Sun.COM 		if (lp->has_arg == required_argument) {
778*7836SJohn.Forte@Sun.COM 			optionStringAll[++j] = ':';
779*7836SJohn.Forte@Sun.COM 		}
780*7836SJohn.Forte@Sun.COM 	}
781*7836SJohn.Forte@Sun.COM 
782*7836SJohn.Forte@Sun.COM 	i = 0;
783*7836SJohn.Forte@Sun.COM 	/*
784*7836SJohn.Forte@Sun.COM 	 * Run getopt for all arguments against all possible options
785*7836SJohn.Forte@Sun.COM 	 * Store all options/option arguments in an array for retrieval
786*7836SJohn.Forte@Sun.COM 	 * later.
787*7836SJohn.Forte@Sun.COM 	 * Once all options are retrieved, check against object
788*7836SJohn.Forte@Sun.COM 	 * and subcommand (option rules table) for validity.
789*7836SJohn.Forte@Sun.COM 	 * This is done later.
790*7836SJohn.Forte@Sun.COM 	 */
791*7836SJohn.Forte@Sun.COM 	while ((opt = getopt_long(getoptargc, getoptargv, optionStringAll,
792*7836SJohn.Forte@Sun.COM 	    _longOptions, NULL)) != EOF) {
793*7836SJohn.Forte@Sun.COM 		switch (opt) {
794*7836SJohn.Forte@Sun.COM 			case '?':
795*7836SJohn.Forte@Sun.COM 				if (optopt == '?') {
796*7836SJohn.Forte@Sun.COM 					subUsageObject(DETAIL_USAGE,
797*7836SJohn.Forte@Sun.COM 					    subcommand, object);
798*7836SJohn.Forte@Sun.COM 					return (0);
799*7836SJohn.Forte@Sun.COM 				} else {
800*7836SJohn.Forte@Sun.COM 					subUsage(GENERAL_USAGE, subcommand);
801*7836SJohn.Forte@Sun.COM 					return (0);
802*7836SJohn.Forte@Sun.COM 				}
803*7836SJohn.Forte@Sun.COM 			default:
804*7836SJohn.Forte@Sun.COM 				cmdOptions[i].optval = opt;
805*7836SJohn.Forte@Sun.COM 				if (optarg) {
806*7836SJohn.Forte@Sun.COM 					len = strlen(optarg);
807*7836SJohn.Forte@Sun.COM 					if (len > sizeof (cmdOptions[i].optarg)
808*7836SJohn.Forte@Sun.COM 					    - 1) {
809*7836SJohn.Forte@Sun.COM 						(void) fprintf(stderr,
810*7836SJohn.Forte@Sun.COM 						    "%s: %s\n",
811*7836SJohn.Forte@Sun.COM 						    commandName,
812*7836SJohn.Forte@Sun.COM 						    gettext("option too long"));
813*7836SJohn.Forte@Sun.COM 						errno = EINVAL;
814*7836SJohn.Forte@Sun.COM 						return (-1);
815*7836SJohn.Forte@Sun.COM 					}
816*7836SJohn.Forte@Sun.COM 					(void) strncpy(cmdOptions[i].optarg,
817*7836SJohn.Forte@Sun.COM 					    optarg, len);
818*7836SJohn.Forte@Sun.COM 				}
819*7836SJohn.Forte@Sun.COM 				i++;
820*7836SJohn.Forte@Sun.COM 				break;
821*7836SJohn.Forte@Sun.COM 		}
822*7836SJohn.Forte@Sun.COM 	}
823*7836SJohn.Forte@Sun.COM 
824*7836SJohn.Forte@Sun.COM 	/*
825*7836SJohn.Forte@Sun.COM 	 * increment past last option
826*7836SJohn.Forte@Sun.COM 	 */
827*7836SJohn.Forte@Sun.COM 	operInd = optind + 2;
828*7836SJohn.Forte@Sun.COM 
829*7836SJohn.Forte@Sun.COM 	/*
830*7836SJohn.Forte@Sun.COM 	 * Check validity of given options, if any were given
831*7836SJohn.Forte@Sun.COM 	 */
832*7836SJohn.Forte@Sun.COM 
833*7836SJohn.Forte@Sun.COM 	/* get option string for this object and subcommand */
834*7836SJohn.Forte@Sun.COM 	availOptions = getOptions(object->value, subcommand->value);
835*7836SJohn.Forte@Sun.COM 
836*7836SJohn.Forte@Sun.COM 	if (cmdOptions[0].optval != 0) { /* options were input */
837*7836SJohn.Forte@Sun.COM 		if (availOptions == NULL) { /* no options permitted */
838*7836SJohn.Forte@Sun.COM 			(void) fprintf(stderr, "%s: %s\n",
839*7836SJohn.Forte@Sun.COM 			    commandName, gettext("no options permitted"));
840*7836SJohn.Forte@Sun.COM 			subUsageObject(HELP_USAGE, subcommand, object);
841*7836SJohn.Forte@Sun.COM 			return (1);
842*7836SJohn.Forte@Sun.COM 		}
843*7836SJohn.Forte@Sun.COM 		for (i = 0; cmdOptions[i].optval; i++) {
844*7836SJohn.Forte@Sun.COM 			/* Check for invalid options */
845*7836SJohn.Forte@Sun.COM 			if (availOptions->optionString == NULL) {
846*7836SJohn.Forte@Sun.COM 				/*
847*7836SJohn.Forte@Sun.COM 				 * internal option table error
848*7836SJohn.Forte@Sun.COM 				 * There must be an option string if
849*7836SJohn.Forte@Sun.COM 				 * there is an entry in the table
850*7836SJohn.Forte@Sun.COM 				 */
851*7836SJohn.Forte@Sun.COM 				assert(0);
852*7836SJohn.Forte@Sun.COM 			}
853*7836SJohn.Forte@Sun.COM 			/* is the option in the available option string? */
854*7836SJohn.Forte@Sun.COM 
855*7836SJohn.Forte@Sun.COM 			if (!(strchr(availOptions->optionString,
856*7836SJohn.Forte@Sun.COM 			    cmdOptions[i].optval))) {
857*7836SJohn.Forte@Sun.COM 				(void) fprintf(stderr,
858*7836SJohn.Forte@Sun.COM 				    "%s: '-%c': %s\n",
859*7836SJohn.Forte@Sun.COM 				    commandName, cmdOptions[i].optval,
860*7836SJohn.Forte@Sun.COM 				    gettext("invalid option"));
861*7836SJohn.Forte@Sun.COM 				subUsageObject(DETAIL_USAGE, subcommand,
862*7836SJohn.Forte@Sun.COM 				    object);
863*7836SJohn.Forte@Sun.COM 				return (1);
864*7836SJohn.Forte@Sun.COM 
865*7836SJohn.Forte@Sun.COM 			/* Check for exclusive options */
866*7836SJohn.Forte@Sun.COM 			} else if (cmdOptions[1].optval != 0 &&
867*7836SJohn.Forte@Sun.COM 
868*7836SJohn.Forte@Sun.COM 			    availOptions->exclusive &&
869*7836SJohn.Forte@Sun.COM 			    strchr(availOptions->exclusive,
870*7836SJohn.Forte@Sun.COM 			    cmdOptions[i].optval)) {
871*7836SJohn.Forte@Sun.COM 
872*7836SJohn.Forte@Sun.COM 				(void) fprintf(stderr,
873*7836SJohn.Forte@Sun.COM 
874*7836SJohn.Forte@Sun.COM 				    "%s: '-%c': %s\n",
875*7836SJohn.Forte@Sun.COM 				    commandName, cmdOptions[i].optval,
876*7836SJohn.Forte@Sun.COM 				    gettext("is an exclusive option"));
877*7836SJohn.Forte@Sun.COM 
878*7836SJohn.Forte@Sun.COM 				subUsageObject(DETAIL_USAGE, subcommand,
879*7836SJohn.Forte@Sun.COM 				    object);
880*7836SJohn.Forte@Sun.COM 				return (1);
881*7836SJohn.Forte@Sun.COM 			}
882*7836SJohn.Forte@Sun.COM 		}
883*7836SJohn.Forte@Sun.COM 	} else { /* no options were input */
884*7836SJohn.Forte@Sun.COM 		if (availOptions != NULL &&
885*7836SJohn.Forte@Sun.COM 		    (availOptions->required)) {
886*7836SJohn.Forte@Sun.COM 			(void) fprintf(stderr, "%s: %s\n",
887*7836SJohn.Forte@Sun.COM 			    commandName,
888*7836SJohn.Forte@Sun.COM 			    gettext("at least one option required"));
889*7836SJohn.Forte@Sun.COM 
890*7836SJohn.Forte@Sun.COM 			subUsageObject(DETAIL_USAGE, subcommand,
891*7836SJohn.Forte@Sun.COM 			    object);
892*7836SJohn.Forte@Sun.COM 			return (1);
893*7836SJohn.Forte@Sun.COM 		}
894*7836SJohn.Forte@Sun.COM 	}
895*7836SJohn.Forte@Sun.COM 
896*7836SJohn.Forte@Sun.COM 	/*
897*7836SJohn.Forte@Sun.COM 	 * If there are no more arguments (operands),
898*7836SJohn.Forte@Sun.COM 	 * check to see if this is okay
899*7836SJohn.Forte@Sun.COM 	 */
900*7836SJohn.Forte@Sun.COM 	if ((operInd == argc) &&
901*7836SJohn.Forte@Sun.COM 	    (opCmd->reqOpCmd & subcommand->value)) {
902*7836SJohn.Forte@Sun.COM 		(void) fprintf(stderr, "%s: %s %s %s\n",
903*7836SJohn.Forte@Sun.COM 		    commandName, subcommand->name,
904*7836SJohn.Forte@Sun.COM 		    object->name, gettext("requires an operand"));
905*7836SJohn.Forte@Sun.COM 
906*7836SJohn.Forte@Sun.COM 		subUsageObject(HELP_USAGE, subcommand, object);
907*7836SJohn.Forte@Sun.COM 		(void) atexit(seeMan);
908*7836SJohn.Forte@Sun.COM 		return (1);
909*7836SJohn.Forte@Sun.COM 	}
910*7836SJohn.Forte@Sun.COM 
911*7836SJohn.Forte@Sun.COM 	/*
912*7836SJohn.Forte@Sun.COM 	 * If there are more operands,
913*7836SJohn.Forte@Sun.COM 	 * check to see if this is okay
914*7836SJohn.Forte@Sun.COM 	 */
915*7836SJohn.Forte@Sun.COM 	if ((argc > operInd) &&
916*7836SJohn.Forte@Sun.COM 	    (opCmd->noOpCmd & subcommand->value)) {
917*7836SJohn.Forte@Sun.COM 		(void) fprintf(stderr, "%s: %s %s %s\n",
918*7836SJohn.Forte@Sun.COM 		    commandName, subcommand->name,
919*7836SJohn.Forte@Sun.COM 		    object->name, gettext("takes no operands"));
920*7836SJohn.Forte@Sun.COM 		subUsageObject(HELP_USAGE, subcommand, object);
921*7836SJohn.Forte@Sun.COM 		return (1);
922*7836SJohn.Forte@Sun.COM 	}
923*7836SJohn.Forte@Sun.COM 
924*7836SJohn.Forte@Sun.COM 	/*
925*7836SJohn.Forte@Sun.COM 	 * If there is more than one more operand,
926*7836SJohn.Forte@Sun.COM 	 * check to see if this is okay
927*7836SJohn.Forte@Sun.COM 	 */
928*7836SJohn.Forte@Sun.COM 	if ((argc > operInd) && ((argc - operInd) != 1) &&
929*7836SJohn.Forte@Sun.COM 	    !(opCmd->multOpCmd & subcommand->value)) {
930*7836SJohn.Forte@Sun.COM 		(void) fprintf(stderr, "%s: %s %s %s\n",
931*7836SJohn.Forte@Sun.COM 		    commandName, subcommand->name, object->name,
932*7836SJohn.Forte@Sun.COM 		    gettext("accepts only a single operand"));
933*7836SJohn.Forte@Sun.COM 		subUsageObject(HELP_USAGE, subcommand, object);
934*7836SJohn.Forte@Sun.COM 		return (1);
935*7836SJohn.Forte@Sun.COM 	}
936*7836SJohn.Forte@Sun.COM 
937*7836SJohn.Forte@Sun.COM 	/* Finished syntax checks */
938*7836SJohn.Forte@Sun.COM 
939*7836SJohn.Forte@Sun.COM 
940*7836SJohn.Forte@Sun.COM 	/* Call appropriate function */
941*7836SJohn.Forte@Sun.COM 
942*7836SJohn.Forte@Sun.COM 	return (subcommand->handler(argc - operInd, &argv[operInd],
943*7836SJohn.Forte@Sun.COM 	    object->value, &cmdOptions[0], callArgs, funcRet));
944*7836SJohn.Forte@Sun.COM }
945