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