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