diff options
| author | John Forte <John.Forte@Sun.COM> | 2008-10-14 15:09:13 -0700 | 
|---|---|---|
| committer | John Forte <John.Forte@Sun.COM> | 2008-10-14 15:09:13 -0700 | 
| commit | fcf3ce441efd61da9bb2884968af01cb7c1452cc (patch) | |
| tree | 0e80d59ad41702571586195bf099ccc14222ce02 /usr/src/cmd/mpathadm/cmdparse.c | |
| parent | 247b82a1f1cb5ebd2d163bd9afdb1a3065611962 (diff) | |
| download | illumos-joyent-fcf3ce441efd61da9bb2884968af01cb7c1452cc.tar.gz | |
6745433 Merge NWS consolidation into OS/Net consolidation
Diffstat (limited to 'usr/src/cmd/mpathadm/cmdparse.c')
| -rw-r--r-- | usr/src/cmd/mpathadm/cmdparse.c | 932 | 
1 files changed, 932 insertions, 0 deletions
| diff --git a/usr/src/cmd/mpathadm/cmdparse.c b/usr/src/cmd/mpathadm/cmdparse.c new file mode 100644 index 0000000000..9080e1cfdd --- /dev/null +++ b/usr/src/cmd/mpathadm/cmdparse.c @@ -0,0 +1,932 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2008 Sun Microsystems, Inc.  All rights reserved. + * Use is subject to license terms. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <sys/types.h> +#include <unistd.h> +#include <libintl.h> +#include <errno.h> +#include <string.h> +#include <assert.h> +#include <getopt.h> +#include "cmdparse.h" + +/* Usage types */ +#define	GENERAL_USAGE	1 +#define	HELP_USAGE	2 +#define	DETAIL_USAGE	3 + +/* printable ascii character set len */ +#define	MAXOPTIONS	(uint_t)('~' - '!' + 1) + +/* + * MAXOPTIONSTRING is the max length of the options string used in getopt and + * will be the printable character set + ':' for each character, + * providing for options with arguments. e.g. "t:Cs:hglr:" + */ +#define	MAXOPTIONSTRING		MAXOPTIONS * 2 + +/* standard command options table to support -?, -V */ +struct option standardCmdOptions[] = { +	{"help", no_argument, NULL, '?'}, +	{"version", no_argument, NULL, 'V'}, +	{NULL, 0, NULL, 0} +}; + +/* standard subcommand options table to support -? */ +struct option standardSubCmdOptions[] = { +	{"help", no_argument, NULL, '?'}, +	{NULL, 0, NULL, 0} +}; + +/* forward declarations */ +static int getSubcommand(char *, subcommand_t **); +static char *getExecBasename(char *); +static void usage(uint_t); +static void subUsage(uint_t, subcommand_t *); +static void subUsageObject(uint_t, subcommand_t *, object_t *); +static int getObject(char *, object_t **); +static int getObjectRules(uint_t, objectRules_t **); +static char *getLongOption(int); +static optionProp_t *getOptions(uint_t, uint_t); +static char *getOptionArgDesc(int); + +/* global data */ +static struct option *_longOptions; +static subcommand_t *_subcommands; +static object_t *_objects; +static objectRules_t *_objectRules; +static optionRules_t *_optionRules; +static optionTbl_t *_clientOptionTbl; +static char *commandName; + + +/* + * input: + *  object - object value + * output: + *  opCmd - pointer to opCmd_t structure allocated by caller + * + * On successful return, opCmd contains the rules for the value in + * object. On failure, the contents of opCmd is unspecified. + * + * Returns: + *  zero on success + *  non-zero on failure + * + */ +static int +getObjectRules(uint_t object, objectRules_t **objectRules) +{ +	objectRules_t *sp; + +	for (sp = _objectRules; sp->value; sp++) { +		if (sp->value == object) { +			*objectRules = sp; +			return (0); +		} +	} +	return (1); +} + +/* + * input: + *  arg - pointer to array of char containing object string + * + * output: + *  object - pointer to object_t structure pointer + *	on success, contains the matching object structure based on + *	input object name + * + * Returns: + *  zero on success + *  non-zero otherwise + * + */ +static int +getObject(char *arg, object_t **object) +{ + +	object_t *op; +	int len; + +	for (op = _objects; op->name; op++) { +		len = strlen(arg); +		if (len == strlen(op->name) && +		    strncasecmp(arg, op->name, len) == 0) { +			*object = op; +			return (0); +		} +	} +	return (1); +} + +/* + * input: + *  arg - pointer to array of char containing subcommand string + * output: + *  subcommand - pointer to subcommand_t pointer + *	on success, contains the matching subcommand structure based on + *	input subcommand name + * + * Returns: + *  zero on success + *  non-zero on failure + */ +static int +getSubcommand(char *arg, subcommand_t **subcommand) +{ +	subcommand_t *sp; +	int len; + +	for (sp = _subcommands; sp->name; sp++) { +		len = strlen(arg); +		if (len == strlen(sp->name) && +		    strncasecmp(arg, sp->name, len) == 0) { +			*subcommand = sp; +			return (0); +		} +	} +	return (1); +} + +/* + * input: + *  object - object for which to get options + *  subcommand - subcommand for which to get options + * + * Returns: + *  on success, optionsProp_t pointer to structure matching input object + *  value + *  on failure, NULL is returned + */ +static optionProp_t * +getOptions(uint_t object, uint_t subcommand) +{ +	uint_t currObject; +	optionRules_t *op = _optionRules; +	while (op && ((currObject = op->objectValue) != 0)) { +		if ((currObject == object) && +		    (op->subcommandValue == subcommand)) { +		    return (&(op->optionProp)); +		} +		op++; +	} +	return (NULL); +} + +/* + * input: + *  shortOption - short option character for which to return the + *	associated long option string + * + * Returns: + *  on success, long option name + *  on failure, NULL + */ +static char * +getLongOption(int shortOption) +{ +	struct option *op; +	for (op = _longOptions; op->name; op++) { +		if (shortOption == op->val) { +			return (op->name); +		} +	} +	return (NULL); +} + +/* + * input + *  shortOption - short option character for which to return the + *	option argument + * Returns: + *  on success, argument string + *  on failure, NULL + */ +static char * +getOptionArgDesc(int shortOption) +{ +	optionTbl_t *op; +	for (op = _clientOptionTbl; op->name; op++) { +		if (op->val == shortOption && +		    op->has_arg == required_argument) { +			return (op->argDesc); +		} +	} +	return (NULL); +} + + +/* + * Print usage for a subcommand. + * + * input: + *  usage type - GENERAL_USAGE, HELP_USAGE, DETAIL_USAGE + *  subcommand - pointer to subcommand_t structure + * + * Returns: + *  none + * + */ +static void +subUsage(uint_t usageType, subcommand_t *subcommand) +{ +	int i; +	object_t *objp; + + +	(void) fprintf(stdout, "%s:\t%s %s [", +	    gettext("Usage"), commandName, subcommand->name); + +	for (i = 0; standardSubCmdOptions[i].name; i++) { +		(void) fprintf(stdout, "-%c", +		    standardSubCmdOptions[i].val); +		if (standardSubCmdOptions[i+1].name) +			(void) fprintf(stdout, ","); +	} + +	(void) fprintf(stdout, "] %s [", "<OBJECT>"); + +	for (i = 0; standardSubCmdOptions[i].name; i++) { +		(void) fprintf(stdout, "-%c", +		    standardSubCmdOptions[i].val); +		if (standardSubCmdOptions[i+1].name) +			(void) fprintf(stdout, ","); +	} + +	(void) fprintf(stdout, "] %s", "[<OPERAND>]"); +	(void) fprintf(stdout, "\n"); + +	if (usageType == GENERAL_USAGE) { +		return; +	} + +	(void) fprintf(stdout, "%s:\n", gettext("Usage by OBJECT")); + +	/* +	 * iterate through object table +	 * For each object, print appropriate usage +	 * based on rules tables +	 */ +	for (objp = _objects; objp->value; objp++) { +		subUsageObject(usageType, subcommand, objp); +	} +} + +/* + * Print usage for a subcommand and object. + * + * input: + *  usage type - GENERAL_USAGE, HELP_USAGE, DETAIL_USAGE + *  subcommand - pointer to subcommand_t structure + *  objp - pointer to a object_t structure + * + * Returns: + *  none + * + */ +static void +subUsageObject(uint_t usageType, subcommand_t *subcommand, object_t *objp) +{ +	int i; +	objectRules_t *objRules = NULL; +	opCmd_t *opCmd = NULL; +	optionProp_t *options; +	char *optionArgDesc; +	char *longOpt; + + +	if (getObjectRules(objp->value, &objRules) != 0) { +		/* +		 * internal subcommand rules table error +		 * no object entry in object +		 */ +		assert(0); +	} + +	opCmd = &(objRules->opCmd); + +	if (opCmd->invOpCmd & subcommand->value) { +		return; +	} + +	options = getOptions(objp->value, subcommand->value); + +	/* print generic subcommand usage */ +	(void) fprintf(stdout, "\t%s %s ", commandName, subcommand->name); + +	/* print object */ +	(void) fprintf(stdout, "%s ", objp->name); + +	/* print options if applicable */ +	if (options != NULL) { +		if (options->required) { +			(void) fprintf(stdout, "%s", gettext("<")); +		} else { +			(void) fprintf(stdout, "%s", gettext("[")); +		} +		(void) fprintf(stdout, "%s", gettext("OPTIONS")); +		if (options->required) { +			(void) fprintf(stdout, "%s ", gettext(">")); +		} else { +			(void) fprintf(stdout, "%s ", gettext("]")); +		} +	} + +	/* print operand requirements */ +	if (opCmd->optOpCmd & subcommand->value) { +		(void) fprintf(stdout, gettext("[")); +	} +	if (!(opCmd->noOpCmd & subcommand->value)) { +		(void) fprintf(stdout, gettext("<")); +		if (objRules->operandDefinition) { +			(void) fprintf(stdout, "%s", +			    objRules->operandDefinition); +		} else { +			/* +			 * Missing operand description +			 * from table +			 */ +			assert(0); +		} +	} +	if (opCmd->multOpCmd & subcommand->value) { +		(void) fprintf(stdout, gettext(" ...")); +	} +	if (!(opCmd->noOpCmd & subcommand->value)) { +		(void) fprintf(stdout, gettext(">")); +	} +	if (opCmd->optOpCmd & subcommand->value) { +		(void) fprintf(stdout, gettext("]")); +	} + +	if (usageType == HELP_USAGE) { +		(void) fprintf(stdout, "\n"); +		return; +	} + +	/* print options for subcommand, object */ +	if (options != NULL && options->optionString != NULL) { +		(void) fprintf(stdout, "\n\t%s:", gettext("OPTIONS")); +		for (i = 0; i < strlen(options->optionString); i++) { +			if ((longOpt = getLongOption( +					    options->optionString[i])) +			    == NULL) { +			    /* no long option exists for short option */ +			    assert(0); +			} +			(void) fprintf(stdout, "\n\t\t-%c, --%s  ", +			    options->optionString[i], longOpt); +			optionArgDesc = +			    getOptionArgDesc(options->optionString[i]); +			if (optionArgDesc != NULL) { +				(void) fprintf(stdout, "<%s>", optionArgDesc); +			} +			if (options->exclusive && +			    strchr(options->exclusive, +				    options->optionString[i])) { +				(void) fprintf(stdout, " (%s)", +				gettext("exclusive")); +			} +		} +	} +	(void) fprintf(stdout, "\n"); +} + +/* + * input: + *  type of usage statement to print + * + * Returns: + *  return value of subUsage + */ +static void +usage(uint_t usageType) +{ +	int i; +	subcommand_t subcommand; +	subcommand_t *sp; + +	/* print general command usage */ +	(void) fprintf(stdout, "%s:\t%s ", +	    gettext("Usage"), commandName); + +	for (i = 0; standardCmdOptions[i].name; i++) { +		(void) fprintf(stdout, "-%c", +		    standardCmdOptions[i].val); +		if (standardCmdOptions[i+1].name) +			(void) fprintf(stdout, ","); +	} + +	if (usageType == HELP_USAGE || usageType == GENERAL_USAGE) { +		for (i = 0; standardSubCmdOptions[i].name; i++) { +			(void) fprintf(stdout, ",--%s", +				standardSubCmdOptions[i].name); +			if (standardSubCmdOptions[i+1].name) +				(void) fprintf(stdout, ","); +		} +	} + +	(void) fprintf(stdout, "\n"); + + +	/* print all subcommand usage */ +	for (sp = _subcommands; sp->name; sp++) { +		subcommand.name = sp->name; +		subcommand.value = sp->value; +		if (usageType == HELP_USAGE) { +			(void) fprintf(stdout, "\n"); +		} +		subUsage(usageType, &subcommand); +	} +} + +/* + * input: + *  execFullName - exec name of program (argv[0]) + * + * Returns: + *  command name portion of execFullName + */ +static char * +getExecBasename(char *execFullname) +{ +	char *lastSlash, *execBasename; + +	/* guard against '/' at end of command invocation */ +	for (;;) { +		lastSlash = strrchr(execFullname, '/'); +		if (lastSlash == NULL) { +			execBasename = execFullname; +			break; +		} else { +			execBasename = lastSlash + 1; +			if (*execBasename == '\0') { +				*lastSlash = '\0'; +				continue; +			} +			break; +		} +	} +	return (execBasename); +} + +/* + * cmdParse is a parser that checks syntax of the input command against + * various rules tables. + * + * It provides usage feedback based upon the passed rules tables by calling + * two usage functions, usage, subUsage, and subUsageObject handling command, + * subcommand and object usage respectively. + * + * When syntax is successfully validated, the associated function is called + * using the subcommands table functions. + * + * Syntax is as follows: + *	command subcommand object [<options>] [<operand>] + * + * There are two standard short and long options assumed: + *	-?, --help	Provides usage on a command or subcommand + *			and stops further processing of the arguments + * + *	-V, --version	Provides version information on the command + *			and stops further processing of the arguments + * + *	These options are loaded by this function. + * + * input: + *  argc, argv from main + *  syntax rules tables (synTables_t structure) + *  callArgs - void * passed by caller to be passed to subcommand function + * + * output: + *  funcRet - pointer to int that holds subcommand function return value + * + * Returns: + * + *     zero on successful syntax parse and function call + * + *     1 on unsuccessful syntax parse (no function has been called) + *		This could be due to a version or help call or simply a + *		general usage call. + * + *     -1 check errno, call failed + * + *  This module is not MT-safe. + * + */ +int +cmdParse(int argc, char *argv[], synTables_t synTable, void *callArgs, +    int *funcRet) +{ +	int	getoptargc; +	char	**getoptargv; +	int	opt; +	int	operInd; +	int	i, j; +	int	len; +	char	*versionString; +	char	optionStringAll[MAXOPTIONSTRING + 1]; +	optionProp_t	*availOptions; +	objectRules_t *objRules = NULL; +	opCmd_t *opCmd = NULL; +	subcommand_t *subcommand; +	object_t *object; +	cmdOptions_t cmdOptions[MAXOPTIONS + 1]; +	struct option *lp; +	optionTbl_t *optionTbl; +	struct option intLongOpt[MAXOPTIONS + 1]; + +	/* +	 * Check for NULLs on mandatory input arguments +	 * +	 * Note: longOptionTbl and optionRulesTbl can be NULL in the case +	 * where there is no caller defined options +	 * +	 */ +	if (synTable.versionString == NULL || +	    synTable.subcommandTbl == NULL || +	    synTable.objectRulesTbl == NULL || +	    synTable.objectTbl == NULL || +	    funcRet == NULL) { +		assert(0); +	} + + +	versionString = synTable.versionString; + +	/* set global command name */ +	commandName = getExecBasename(argv[0]); + +	/* Set unbuffered output */ +	setbuf(stdout, NULL); + +	/* load globals */ +	_subcommands = synTable.subcommandTbl; +	_objectRules = synTable.objectRulesTbl; +	_optionRules = synTable.optionRulesTbl; +	_objects = synTable.objectTbl; +	_clientOptionTbl = synTable.longOptionTbl; + +	/* There must be at least two arguments */ +	if (argc < 2) { +		usage(GENERAL_USAGE); +		return (1); +	} + +	(void) memset(&intLongOpt[0], 0, sizeof (intLongOpt)); + +	/* +	 * load standard subcommand options to internal long options table +	 * Two separate getopt_long(3C) tables are used. +	 */ +	for (i = 0; standardSubCmdOptions[i].name; i++) { +		intLongOpt[i].name = standardSubCmdOptions[i].name; +		intLongOpt[i].has_arg = standardSubCmdOptions[i].has_arg; +		intLongOpt[i].flag = standardSubCmdOptions[i].flag; +		intLongOpt[i].val = standardSubCmdOptions[i].val; +	} + +	/* +	 * copy caller's long options into internal long options table +	 * We do this for two reasons: +	 *  1) We need to use the getopt_long option structure internally +	 *  2) We need to prepend the table with the standard option +	 *	for all subcommands (currently -?) +	 */ +	for (optionTbl = synTable.longOptionTbl; +	    optionTbl && optionTbl->name; optionTbl++, i++) { +		if (i > MAXOPTIONS - 1) { +			/* option table too long */ +			assert(0); +		} +		intLongOpt[i].name = optionTbl->name; +		intLongOpt[i].has_arg = optionTbl->has_arg; +		intLongOpt[i].flag = NULL; +		intLongOpt[i].val = optionTbl->val; +	} + +	/* set option table global */ +	_longOptions = &intLongOpt[0]; + + +	/* +	 * Check for help/version request immediately following command +	 * '+' in option string ensures POSIX compliance in getopt_long() +	 * which means that processing will stop at first non-option +	 * argument. +	 */ +	while ((opt = getopt_long(argc, argv, "+?V", standardCmdOptions, +			    NULL)) != EOF) { +		switch (opt) { +			case '?': +				/* +				 * getopt can return a '?' when no +				 * option letters match string. Check for +				 * the 'real' '?' in optopt. +				 */ +				if (optopt == '?') { +					usage(HELP_USAGE); +					return (1); +				} else { +					usage(GENERAL_USAGE); +					return (1); +				} +			case 'V': +				(void) fprintf(stdout, "%s: %s %s\n", +				    commandName, gettext("Version"), +				    versionString); +				return (1); +			default: +				break; +		} +	} + +	/* +	 * subcommand is always in the second argument. If there is no +	 * recognized subcommand in the second argument, print error, +	 * general usage and then return. +	 */ +	if (getSubcommand(argv[1], &subcommand) != 0) { +		(void) fprintf(stderr, "%s: %s\n", +		    commandName, gettext("invalid subcommand")); +		usage(GENERAL_USAGE); +		return (1); +	} + +	if (argc == 2) { +		(void) fprintf(stderr, "%s: %s\n", +		    commandName, gettext("missing object")); +		subUsage(GENERAL_USAGE, subcommand); +		return (1); +	} + +	getoptargv = argv; +	getoptargv++; +	getoptargc = argc; +	getoptargc -= 1; + +	while ((opt = getopt_long(getoptargc, getoptargv, "+?", +			    standardSubCmdOptions, NULL)) != EOF) { +		switch (opt) { +			case '?': +				/* +				 * getopt can return a '?' when no +				 * option letters match string. Check for +				 * the 'real' '?' in optopt. +				 */ +				if (optopt == '?') { +					subUsage(HELP_USAGE, subcommand); +					return (1); +				} else { +					subUsage(GENERAL_USAGE, subcommand); +					return (1); +				} +			default: +				break; +		} +	} + + +	/* +	 * object is always in the third argument. If there is no +	 * recognized object in the third argument, print error, +	 * help usage for the subcommand and then return. +	 */ +	if (getObject(argv[2], &object) != 0) { +	    (void) fprintf(stderr, "%s: %s\n", +		commandName, gettext("invalid object")); +	    subUsage(HELP_USAGE, subcommand); +	    return (1); +	} + +	if (getObjectRules(object->value, &objRules) != 0) { +		/* +		 * internal subcommand rules table error +		 * no object entry in object table +		 */ +		assert(0); +	} + +	opCmd = &(objRules->opCmd); + +	/* +	 * Is command valid for this object? +	 */ +	if (opCmd->invOpCmd & subcommand->value) { +		(void) fprintf(stderr, "%s: %s %s\n", commandName, +		    gettext("invalid subcommand for"), object->name); +		subUsage(HELP_USAGE, subcommand); +		return (1); +	} + +	/* +	 * offset getopt arg begin since +	 * getopt(3C) assumes options +	 * follow first argument +	 */ +	getoptargv = argv; +	getoptargv++; +	getoptargv++; +	getoptargc = argc; +	getoptargc -= 2; + +	(void) memset(optionStringAll, 0, sizeof (optionStringAll)); +	(void) memset(&cmdOptions[0], 0, sizeof (cmdOptions)); + +	j = 0; +	/* +	 * Build optionStringAll from long options table +	 */ +	for (lp = _longOptions;  lp->name; lp++, j++) { +		/* sanity check on string length */ +		if (j + 1 >= sizeof (optionStringAll)) { +			/* option table too long */ +			assert(0); +		} +		optionStringAll[j] = lp->val; +		if (lp->has_arg == required_argument) { +			optionStringAll[++j] = ':'; +		} +	} + +	i = 0; +	/* +	 * Run getopt for all arguments against all possible options +	 * Store all options/option arguments in an array for retrieval +	 * later. +	 * Once all options are retrieved, check against object +	 * and subcommand (option rules table) for validity. +	 * This is done later. +	 */ +	while ((opt = getopt_long(getoptargc, getoptargv, optionStringAll, +			    _longOptions, NULL)) != EOF) { +		switch (opt) { +			case '?': +				if (optopt == '?') { +					subUsageObject(DETAIL_USAGE, +					    subcommand, object); +					return (1); +				} else { +					subUsage(GENERAL_USAGE, subcommand); +					return (1); +				} +			default: +				cmdOptions[i].optval = opt; +				if (optarg) { +					len = strlen(optarg); +					if (len > sizeof (cmdOptions[i].optarg) +					    - 1) { +						(void) fprintf(stderr, +						    "%s: %s\n", commandName, +						    gettext("option too long")); +						errno = EINVAL; +						return (-1); +					} +					(void) strncpy(cmdOptions[i].optarg, +					    optarg, len); +				} +				i++; +				break; +		} +	} + +	/* +	 * increment past last option +	 */ +	operInd = optind + 2; + +	/* +	 * Check validity of given options, if any were given +	 */ + +	/* get option string for this object and subcommand */ +	availOptions = getOptions(object->value, subcommand->value); + +	if (cmdOptions[0].optval != 0) { /* options were input */ +		if (availOptions == NULL) { /* no options permitted */ +			(void) fprintf(stderr, "%s: %s\n", +				commandName, gettext("no options permitted")); +			subUsageObject(HELP_USAGE, subcommand, object); +			return (1); +		} +		for (i = 0; cmdOptions[i].optval; i++) { +			/* Check for invalid options */ +			if (availOptions->optionString == NULL) { +				/* +				 * internal option table error +				 * There must be an option string if +				 * there is an entry in the table +				 */ +				assert(0); +			} +			/* is the option in the available option string? */ + +			if (!(strchr(availOptions->optionString, +				cmdOptions[i].optval))) { +				(void) fprintf(stderr, +					"%s: '-%c': %s\n", +					commandName, cmdOptions[i].optval, +					gettext("invalid option")); +				subUsageObject(DETAIL_USAGE, subcommand, +					object); +				return (1); + +			/* Check for exclusive options */ +			} else if (cmdOptions[1].optval != 0 && +				availOptions->exclusive && +				strchr(availOptions->exclusive, +					cmdOptions[i].optval)) { +					(void) fprintf(stderr, +					"%s: '-%c': %s\n", +					commandName, cmdOptions[i].optval, +					gettext("is an exclusive option")); +				subUsageObject(DETAIL_USAGE, subcommand, +					object); +					return (1); +			} +		} +	} else { /* no options were input */ +		if (availOptions != NULL && +			(availOptions->required)) { +			(void) fprintf(stderr, "%s: %s\n", +				commandName, +				gettext("at least one option required")); +			subUsageObject(DETAIL_USAGE, subcommand, +				object); +			return (1); +		} +	} + +	/* +	 * If there are no more arguments (operands), +	 * check to see if this is okay +	 */ +	if ((operInd == argc) && +		(opCmd->reqOpCmd & subcommand->value)) { +		(void) fprintf(stderr, "%s: %s %s %s\n", +			commandName, subcommand->name, +			object->name, gettext("requires an operand")); +		subUsageObject(HELP_USAGE, subcommand, object); +		return (1); +	} + +	/* +	 * If there are more operands, +	 * check to see if this is okay +	 */ +	if ((argc > operInd) && +		(opCmd->noOpCmd & subcommand->value)) { +		(void) fprintf(stderr, "%s: %s %s %s\n", +			commandName, subcommand->name, +			object->name, gettext("takes no operands")); +		subUsageObject(HELP_USAGE, subcommand, object); +		return (1); +	} + +	/* +	 * If there is more than one more operand, +	 * check to see if this is okay +	 */ +	if ((argc > operInd) && ((argc - operInd) != 1) && +		!(opCmd->multOpCmd & subcommand->value)) { +		(void) fprintf(stderr, "%s: %s %s %s\n", +			commandName, subcommand->name, object->name, +			gettext("accepts only a single operand")); +		subUsageObject(HELP_USAGE, subcommand, object); +		return (1); +	} + +	/* Finished syntax checks */ + + +	/* Call appropriate function */ +	*funcRet = subcommand->handler(argc - operInd, &argv[operInd], +		object->value, &cmdOptions[0], callArgs); + +	return (0); +} | 
