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