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