Esempio n. 1
0
int
main(int argc, char *argv[])
{
    synTables_t synTables;
    char versionString[VERSION_STRING_MAX_LEN];
    int ret;
    int funcRet;
    void *subcommandArgs = NULL;

    (void) setlocale(LC_ALL, "");
    (void) textdomain(TEXT_DOMAIN);
    /* set global command name */
    cmdName = getExecBasename(argv[0]);

    (void) snprintf(versionString, VERSION_STRING_MAX_LEN, "%s.%s",
                    VERSION_STRING_MAJOR, VERSION_STRING_MINOR);
    synTables.versionString = versionString;
    synTables.longOptionTbl = options;
    synTables.subCommandPropsTbl = subCommands;

    ret = cmdParse(argc, argv, synTables, subcommandArgs, &funcRet);
    if (ret != 0) {
        return (ret);
    }

    return (funcRet);
} /* end main */
Esempio n. 2
0
/*
 * main calls a parser that checks syntax of the input command against
 * various rules tables.
 *
 * The return value from the function is placed in funcRet
 */
int
main(int argc, char *argv[])
{
    synTables_t synTables;
    char versionString[VERSION_STRING_MAX_LEN];
    int ret;
    int funcRet;
    void *subcommandArgs = NULL;

    /* to support locale */
    (void) setlocale(LC_ALL, "");
#if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
#define	TEXT_DOMAIN "SYS_TEST"	/* Use this only if it weren't */
#endif
    (void) textdomain(TEXT_DOMAIN);

    /* set global command name */
    cmdName = getExecBasename(argv[0]);

    /* check if is global zone */
    if (getzoneid() != GLOBAL_ZONEID) {
        (void *) fprintf(stdout, "%s %s\n",
                         cmdName, gettext("does not support non-global zone."));
        return (1);
    }

    (void *) snprintf(versionString, sizeof (versionString), "%s.%s",
                      VERSION_STRING_MAJOR, VERSION_STRING_MINOR);
    synTables.versionString = versionString;

    synTables.longOptionTbl = &sasinfolongOptions[0];
    synTables.subCommandPropsTbl = &sasinfosubcommands[0];

    /* call the CLI parser */
    ret = cmdParse(argc, argv, synTables, subcommandArgs, &funcRet);
    if (ret == 1) {
        (void *) fprintf(stdout, "%s %s(1M)\n",
                         gettext("For more information, please see"), cmdName);
        return (1);
    } else if (ret == -1) {
        (void *) fprintf(stderr, "%s %s\n",
                         cmdName, strerror(errno));
        return (1);
    }

    if (funcRet != 0) {
        return (1);
    }
    return (0);
}
Esempio n. 3
0
/*
 * main calls a parser that checks syntax of the input command against
 * various rules tables.
 *
 * The parser provides usage feedback based upon same tables by calling
 * two usage functions, usage and subUsage, handling command and subcommand
 * usage respectively.
 *
 * The parser handles all printing of usage syntactical errors
 *
 * When syntax is successfully validated, the parser calls the associated
 * function using the subcommands table functions.
 *
 * Syntax is as follows:
 *	command subcommand [options] resource-type [<object>]
 *
 * The return value from the function is placed in funcRet
 */
int
main(int argc, char *argv[])
{
	synTables_t synTables;
	char versionString[VERSION_STRING_MAX_LEN];
	int ret;
	int funcRet;
	void *subcommandArgs = NULL;

	/* set global command name */
	cmdName = getExecBasename(argv[0]);

	if (getzoneid() != GLOBAL_ZONEID) {
		(void) fprintf(stderr,
		    "%s: this command is only available in the 'global' "
		    "zone\n", cmdName);
		exit(1);
	}

	(void) snprintf(versionString, sizeof (versionString), "%s.%s",
	    VERSION_STRING_MAJOR, VERSION_STRING_MINOR);
	synTables.versionString = versionString;
	synTables.longOptionTbl = &longOptions[0];
	synTables.subcommandTbl = &subcommands[0];
	synTables.objectTbl = &objects[0];
	synTables.objectRulesTbl = &objectRules[0];
	synTables.optionRulesTbl = &optionRules[0];

	/* call the CLI parser */
	ret = cmdParse(argc, argv, synTables, subcommandArgs, &funcRet);
	if (ret == 1) {
		(void) printf("%s %s(1M)\n",
		    gettext("For more information, please see"), cmdName);
		return (1);
	} else if (ret == -1) {
		perror(cmdName);
		return (1);
	}

	return (funcRet);
}
Esempio n. 4
0
/*
 * 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);
	}

	bzero(&intLongOpt[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;

	bzero(optionStringAll, sizeof (optionStringAll));
	bzero(&cmdOptions[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);
}
Esempio n. 5
0
/*
 * 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
 *
 * When syntax is successfully validated, the associated function is called
 * using the subcommands table functions.
 *
 * Syntax is as follows:
 *	command subcommand [<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;
	int	requiredOptionCnt = 0, requiredOptionEntered = 0;
	char	*availOptions;
	char	*versionString;
	char	optionStringAll[MAXOPTIONSTRING + 1];
	subCommandProps_t *subcommand;
	cmdOptions_t cmdOptions[MAXOPTIONS + 1];
	optionTbl_t *optionTbl;
	struct option *lp;
	struct option intLongOpt[MAXOPTIONS + 1];

	/*
	 * Check for NULLs on mandatory input arguments
	 *
	 * Note: longOptionTbl can be NULL in the case
	 * where there is no caller defined options
	 *
	 */
	assert(synTable.versionString);
	assert(synTable.subCommandPropsTbl);
	assert(funcRet);

	versionString = synTable.versionString;

	/* set global command name */
	commandName = getExecBasename(argv[0]);

	/* Set unbuffered output */
	setbuf(stdout, NULL);

	/* load globals */
	_subCommandProps = synTable.subCommandPropsTbl;
	_clientOptionTbl = synTable.longOptionTbl;

	/* There must be at least two arguments */
	if (argc < 2) {
		usage(GENERAL_USAGE);
		return (1);
	}

	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(DETAIL_USAGE);
					exit(0);
				} else {
					usage(GENERAL_USAGE);
					return (1);
				}
				break;
			case 'V':
				fprintf(stdout, "%s: %s %s\n",
				    commandName, gettext("Version"),
				    versionString);
				exit(0);
				break;
			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 (getSubcommandProps(argv[1], &subcommand) != 0) {
		printf("%s: %s\n", commandName, gettext("invalid subcommand"));
		usage(GENERAL_USAGE);
		return (1);
	}

	getoptargv = argv;
	getoptargv++;
	getoptargc = argc;
	getoptargc -= 1;

	memset(optionStringAll, 0, sizeof (optionStringAll));
	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, a validity check against
	 * subcommand table is performed.
	 */
	while ((opt = getopt_long(getoptargc, getoptargv, optionStringAll,
	    _longOptions, NULL)) != EOF) {
		switch (opt) {
			case '?':
				subUsage(DETAIL_USAGE, subcommand);
				exit(0);
			default:
				cmdOptions[i].optval = opt;
				if (optarg) {
					len = strlen(optarg);
					if (len > sizeof (cmdOptions[i].optarg)
					    - 1) {
						printf("%s: %s\n", commandName,
						    gettext("option too long"));
						errno = EINVAL;
						return (-1);
					}
					strncpy(cmdOptions[i].optarg, optarg,
					    len);
				}
				i++;
				break;
		}
	}

	/*
	 * increment past last option
	 */
	operInd = optind + 1;

	/*
	 * Check validity of given options, if any were given
	 */

	/* get option string for this subcommand */
	availOptions = subcommand->optionString;

	/* Get count of required options */
	if (subcommand->required) {
		requiredOptionCnt = strlen(subcommand->required);
	}

	if (cmdOptions[0].optval != 0) { /* options were input */
		if (availOptions == NULL) { /* no options permitted */
			printf("%s: %s\n", commandName,
			    gettext("no options permitted"));
			subUsage(DETAIL_USAGE, subcommand);
			return (1);
		}
		for (i = 0; cmdOptions[i].optval; i++) {
			/* is the option in the available option string? */
			if (!(strchr(availOptions, cmdOptions[i].optval))) {
				printf("%s: '-%c': %s\n", commandName,
				    cmdOptions[i].optval,
				    gettext("invalid option"));
				subUsage(DETAIL_USAGE, subcommand);
				return (1);
			/* increment required options entered */
			} else if (subcommand->required &&
			    (strchr(subcommand->required,
			    cmdOptions[i].optval))) {
				requiredOptionEntered++;
			/* Check for exclusive options */
			} else if (cmdOptions[1].optval != 0 &&
			    subcommand->exclusive &&
			    strchr(subcommand->exclusive,
			    cmdOptions[i].optval)) {
					printf("%s: '-%c': %s\n", commandName,
					    cmdOptions[i].optval,
					    gettext("is an exclusive option"));
				subUsage(DETAIL_USAGE, subcommand);
					return (1);
			}
		}
	} else { /* no options were input */
		if (availOptions != NULL && subcommand->required) {
			printf("%s: %s\n", commandName,
			    gettext("at least one option required"));
			subUsage(DETAIL_USAGE, subcommand);
			return (1);
		}
	}

	/* Were all required options entered? */
	if (requiredOptionEntered != requiredOptionCnt) {
		printf("%s: %s: %s\n", commandName,
		    gettext("Following option(s) required"),
		    subcommand->required);
		subUsage(DETAIL_USAGE, subcommand);
		return (1);
	}


	/*
	 * If there are no operands,
	 * check to see if this is okay
	 */
	if ((operInd == argc) &&
	    (subcommand->operand & OPERAND_MANDATORY)) {
		printf("%s: %s %s\n", commandName, subcommand->name,
		    gettext("requires an operand"));
		subUsage(DETAIL_USAGE, subcommand);
		return (1);
	}

	/*
	 * If there are more operands,
	 * check to see if this is okay
	 */
	if ((argc > operInd) &&
	    (subcommand->operand & OPERAND_NONE)) {
		fprintf(stderr, "%s: %s %s\n", commandName, subcommand->name,
		    gettext("takes no operands"));
		subUsage(DETAIL_USAGE, subcommand);
		return (1);
	}

	/*
	 * If there is more than one more operand,
	 * check to see if this is okay
	 */
	if ((argc > operInd) && ((argc - operInd) != 1) &&
	    (subcommand->operand & OPERAND_SINGLE)) {
		printf("%s: %s %s\n", commandName,
		    subcommand->name, gettext("accepts only a single operand"));
		subUsage(DETAIL_USAGE, subcommand);
		return (1);
	}

	/* Finished syntax checks */


	/* Call appropriate function */
	*funcRet = subcommand->handler(argc - operInd, &argv[operInd],
	    &cmdOptions[0], callArgs);

	return (0);
}