X-Git-Url: http://git.openafs.org/?p=openafs.git;a=blobdiff_plain;f=src%2Fcmd%2Fcmd.c;h=10b2b1bae93a8625c00b7fecddcfb0b8f2495cc7;hp=4389adc8bc564ad9f08c17ea3e4a93bcfeb04336;hb=297c479989efb6bd9d4011a43d6c0dc92596761b;hpb=bdca02dfe7df3800a3e5f3a9b10ca1d223779ef9 diff --git a/src/cmd/cmd.c b/src/cmd/cmd.c index 4389adc..10b2b1b 100644 --- a/src/cmd/cmd.c +++ b/src/cmd/cmd.c @@ -32,6 +32,8 @@ static int enablePositional = 1; static int enableAbbreviation = 1; static void *beforeRock, *afterRock; static char initcmd_opcode[] = "initcmd"; /*Name of initcmd opcode */ +static cmd_config_section *globalConfig = NULL; +static const char *commandName = NULL; /* take name and string, and return null string if name is empty, otherwise return the concatenation of the two strings */ @@ -169,11 +171,12 @@ ParmHelpString(struct cmd_parmdesc *aparm) if (aparm->type == CMD_FLAG) { return strdup(""); } else { - asprintf(&str, " %s<%s>%s%s", - aparm->type == CMD_SINGLE_OR_FLAG?"[":"", - aparm->help?aparm->help:"arg", - aparm->type == CMD_LIST?"+":"", - aparm->type == CMD_SINGLE_OR_FLAG?"]":""); + if (asprintf(&str, " %s<%s>%s%s", + aparm->type == CMD_SINGLE_OR_FLAG?"[":"", + aparm->help?aparm->help:"arg", + aparm->type == CMD_LIST?"+":"", + aparm->type == CMD_SINGLE_OR_FLAG?"]":"") < 0) + return NULL; return str; } } @@ -199,18 +202,14 @@ PrintSyntax(struct cmd_syndesc *as) /* now print usage, from syntax table */ if (noOpcodes) - asprintf(&str, "Usage: %s", as->a0name); + len = printf("Usage: %s", as->a0name); else { if (!strcmp(as->name, initcmd_opcode)) - asprintf(&str, "Usage: %s[%s]", NName(as->a0name, " "), as->name); + len = printf("Usage: %s[%s]", NName(as->a0name, " "), as->name); else - asprintf(&str, "Usage: %s%s", NName(as->a0name, " "), as->name); + len = printf("Usage: %s%s", NName(as->a0name, " "), as->name); } - len = strlen(str); - printf("%s", str); - free(str); - for (i = 0; i < CMD_MAXPARMS; i++) { tp = &as->parms[i]; if (tp->type == 0) @@ -221,6 +220,10 @@ PrintSyntax(struct cmd_syndesc *as) /* The parameter name is the real name, plus any aliases */ if (!tp->aliases) { name = strdup(tp->name); + if (!name) { + fprintf(stderr, "Out of memory.\n"); + return; + } } else { size_t namelen; struct cmd_item *alias; @@ -229,6 +232,10 @@ PrintSyntax(struct cmd_syndesc *as) namelen+=strlen(alias->data) + 3; name = malloc(namelen); + if (!name) { + fprintf(stderr, "Out of memory.\n"); + return; + } strlcpy(name, tp->name, namelen); for (alias = tp->aliases; alias != NULL; alias = alias->next) { @@ -240,6 +247,11 @@ PrintSyntax(struct cmd_syndesc *as) /* Work out if we can fit what we want to on this line, or if we need to * start a new one */ str = ParmHelpString(tp); + if (!str) { + fprintf(stderr, "Out of memory.\n"); + free(name); + return; + } xtralen = 1 + strlen(name) + strlen(str) + ((tp->flags & CMD_OPTIONAL)? 2: 0); @@ -358,11 +370,35 @@ HelpProc(struct cmd_syndesc *as, void *arock) int code = 0; if (as->parms[0].items == 0) { - printf("%sCommands are:\n", NName(as->a0name, ": ")); + struct cmd_syndesc *initcmd = NULL; + int count = 0; + + /* + * Print the usage of the initcmd command when it is the only + * non-hidden, explicit command, otherwise, list the all the commands. + */ for (ts = allSyntax; ts; ts = ts->next) { - if ((ts->flags & CMD_ALIAS) || (ts->flags & CMD_HIDDEN)) + if (ts->flags & (CMD_ALIAS | CMD_HIDDEN | CMD_IMPLICIT)) { + continue; /* skip aliases, hidden, and implied commands */ + } + if (strcmp(ts->name, initcmd_opcode) == 0) { + initcmd = ts; /* save the initcmd */ continue; - printf("%-15s %s\n", ts->name, (ts->help ? ts->help : "")); + } + count++; + } + if (initcmd && count == 0) { + initcmd->a0name = as->a0name; + PrintAliases(initcmd); + PrintSyntax(initcmd); + PrintFlagHelp(initcmd); + } else { + printf("%sCommands are:\n", NName(as->a0name, ": ")); + for (ts = allSyntax; ts; ts = ts->next) { + if ((ts->flags & CMD_ALIAS) || (ts->flags & CMD_HIDDEN)) + continue; + printf("%-15s %s\n", ts->name, (ts->help ? ts->help : "")); + } } } else { /* print out individual help topics */ @@ -431,10 +467,24 @@ SortSyntax(struct cmd_syndesc *as) return 0; } +/*! + * Create a command syntax. + * + * \note Use cmd_AddParm() or cmd_AddParmAtOffset() to set the + * parameters for the new command. + * + * \param[in] aname name used to invoke the command + * \param[in] aproc procedure to be called when command is invoked + * \param[in] arock opaque data pointer to be passed to aproc + * \param[in] aflags command option flags + * \param[in] ahelp help string to display for this command + * + * \return a pointer to the cmd_syndesc or NULL if error. + */ struct cmd_syndesc * cmd_CreateSyntax(char *aname, int (*aproc) (struct cmd_syndesc * ts, void *arock), - void *arock, char *ahelp) + void *arock, afs_uint32 aflags, char *ahelp) { struct cmd_syndesc *td; @@ -442,28 +492,27 @@ cmd_CreateSyntax(char *aname, if (noOpcodes) return NULL; + /* Allow only valid cmd flags. */ + if (aflags & ~(CMD_HIDDEN | CMD_IMPLICIT)) { + return NULL; + } + td = calloc(1, sizeof(struct cmd_syndesc)); assert(td); td->aliasOf = td; /* treat aliasOf as pointer to real command, no matter what */ + td->flags = aflags; /* copy in name, etc */ if (aname) { - td->name = malloc(strlen(aname) + 1); + td->name = strdup(aname); assert(td->name); - strcpy(td->name, aname); } else { td->name = NULL; noOpcodes = 1; } if (ahelp) { - /* Piggy-back the hidden option onto the help string */ - if (ahelp == (char *)CMD_HIDDEN) { - td->flags |= CMD_HIDDEN; - } else { - td->help = malloc(strlen(ahelp) + 1); - assert(td->help); - strcpy(td->help, ahelp); - } + td->help = strdup(ahelp); + assert(td->help); } else td->help = NULL; td->proc = aproc; @@ -486,9 +535,8 @@ cmd_CreateAlias(struct cmd_syndesc *as, char *aname) td = malloc(sizeof(struct cmd_syndesc)); assert(td); memcpy(td, as, sizeof(struct cmd_syndesc)); - td->name = malloc(strlen(aname) + 1); + td->name = strdup(aname); assert(td->name); - strcpy(td->name, aname); td->flags |= CMD_ALIAS; /* if ever free things, make copy of help string, too */ @@ -516,13 +564,6 @@ cmd_DisableAbbreviations(void) } int -cmd_IsAdministratorCommand(struct cmd_syndesc *as) -{ - as->flags |= CMD_ADMIN; - return 0; -} - -int cmd_Seek(struct cmd_syndesc *as, int apos) { if (apos >= CMD_MAXPARMS) @@ -541,16 +582,14 @@ cmd_AddParmAtOffset(struct cmd_syndesc *as, int ref, char *aname, int atype, return CMD_EXCESSPARMS; tp = &as->parms[ref]; - tp->name = malloc(strlen(aname) + 1); + tp->name = strdup(aname); assert(tp->name); - strcpy(tp->name, aname); tp->type = atype; tp->flags = aflags; tp->items = NULL; if (ahelp) { - tp->help = malloc(strlen(ahelp) + 1); + tp->help = strdup(ahelp); assert(tp->help); - strcpy(tp->help, ahelp); } else tp->help = NULL; @@ -605,9 +644,8 @@ AddItem(struct cmd_parmdesc *aparm, char *aval, char *pname) ti = calloc(1, sizeof(struct cmd_item)); assert(ti); - ti->data = malloc(strlen(aval) + 1); + ti->data = strdup(aval); assert(ti->data); - strcpy(ti->data, aval); /* now put ti at the *end* of the list */ if ((ni = aparm->items)) { for (; ni; ni = ni->next) @@ -714,13 +752,12 @@ InsertInitOpcode(int *aargc, char **aargv) } /* Create space for the initial opcode & fill it in */ - pinitopcode = malloc(sizeof(initcmd_opcode)); + pinitopcode = strdup(initcmd_opcode); if (!pinitopcode) { fprintf(stderr, "%s: Can't malloc initial opcode space\n", aargv[0]); free(newargv); return (NULL); } - strcpy(pinitopcode, initcmd_opcode); /* Move all the items in the old argv into the new argv, in their * proper places */ @@ -763,25 +800,20 @@ initSyntax(void) struct cmd_syndesc *ts; if (!noOpcodes) { - ts = cmd_CreateSyntax("help", HelpProc, NULL, + ts = cmd_CreateSyntax("help", HelpProc, NULL, CMD_IMPLICIT, "get help on commands"); cmd_AddParm(ts, "-topic", CMD_LIST, CMD_OPTIONAL, "help string"); - cmd_AddParm(ts, "-admin", CMD_FLAG, CMD_OPTIONAL, NULL); - ts = cmd_CreateSyntax("apropos", AproposProc, NULL, + ts = cmd_CreateSyntax("apropos", AproposProc, NULL, CMD_IMPLICIT, "search by help text"); cmd_AddParm(ts, "-topic", CMD_SINGLE, CMD_REQUIRED, "help string"); - cmd_CreateSyntax("version", VersionProc, NULL, - (char *)CMD_HIDDEN); - cmd_CreateSyntax("-version", VersionProc, NULL, - (char *)CMD_HIDDEN); - cmd_CreateSyntax("-help", HelpProc, NULL, - (char *)CMD_HIDDEN); - cmd_CreateSyntax("--version", VersionProc, NULL, - (char *)CMD_HIDDEN); - cmd_CreateSyntax("--help", HelpProc, NULL, - (char *)CMD_HIDDEN); + cmd_CreateSyntax("version", VersionProc, NULL, CMD_IMPLICIT, + "show version"); + cmd_CreateSyntax("-version", VersionProc, NULL, (CMD_HIDDEN | CMD_IMPLICIT), NULL); + cmd_CreateSyntax("-help", HelpProc, NULL, (CMD_HIDDEN | CMD_IMPLICIT), NULL); + cmd_CreateSyntax("--version", VersionProc, NULL, (CMD_HIDDEN | CMD_IMPLICIT), NULL); + cmd_CreateSyntax("--help", HelpProc, NULL, (CMD_HIDDEN | CMD_IMPLICIT), NULL); } } @@ -1023,7 +1055,7 @@ cmd_Parse(int argc, char **argv, struct cmd_syndesc **outsyntax) /* Display full help syntax if we don't have subcommands */ if (noOpcodes) PrintFlagHelp(ts); - code = CMD_USAGE; + code = CMD_HELP; goto out; } @@ -1066,8 +1098,12 @@ cmd_Dispatch(int argc, char **argv) int code; code = cmd_Parse(argc, argv, &ts); - if (code) + if (code) { + if (code == CMD_HELP) { + code = 0; /* displaying help is not an error */ + } return code; + } /* * Before calling the beforeProc and afterProc and all the implications @@ -1142,9 +1178,8 @@ CopyBackArgs(struct cmd_token *alist, char **argv, count = 0; if (amaxn <= 1) return CMD_TOOMANY; - *argv = (char *)malloc(strlen(INITSTR) + 1); + *argv = strdup(INITSTR); assert(*argv); - strcpy(*argv, INITSTR); amaxn--; argv++; count++; @@ -1209,9 +1244,8 @@ cmd_ParseLine(char *aline, char **argv, afs_int32 * an, afs_int32 amaxn) ttok = malloc(sizeof(struct cmd_token)); assert(ttok); ttok->next = NULL; - ttok->key = malloc(strlen(tbuffer) + 1); + ttok->key = strdup(tbuffer); assert(ttok->key); - strcpy(ttok->key, tbuffer); if (last) { last->next = ttok; last = ttok; @@ -1247,18 +1281,96 @@ cmd_ParseLine(char *aline, char **argv, afs_int32 * an, afs_int32 amaxn) } } -int -cmd_OptionAsInt(struct cmd_syndesc *syn, int pos, int *value) +/* Read a string in from our configuration file. This checks in + * multiple places within this file - firstly in the section + * [command_subcommand], then in [command], then in [subcommand] + * + * Returns CMD_MISSING if there is no configuration file configured, + * or if the file doesn't contain information for the specified option + * in any of these sections. + */ + +static int +_get_file_string(struct cmd_syndesc *syn, int pos, const char **str) { + char *section; + char *optionName; + + /* Nothing on the command line, try the config file if we have one */ + if (globalConfig == NULL) + return CMD_MISSING; + + /* March past any leading -'s */ + for (optionName = syn->parms[pos].name; + *optionName == '-'; optionName++); + + /* First, try the command_subcommand form */ + if (syn->name != NULL && commandName != NULL) { + if (asprintf(§ion, "%s_%s", commandName, syn->name) < 0) + return ENOMEM; + *str = cmd_RawConfigGetString(globalConfig, NULL, section, + optionName, NULL); + free(section); + if (*str) + return 0; + } + + /* Then, try the command form */ + if (commandName != NULL) { + *str = cmd_RawConfigGetString(globalConfig, NULL, commandName, + optionName, NULL); + if (*str) + return 0; + } + + /* Then, the defaults section */ + *str = cmd_RawConfigGetString(globalConfig, NULL, "defaults", + optionName, NULL); + if (*str) + return 0; + + /* Nothing there, return MISSING */ + return CMD_MISSING; +} + +static int +_get_config_string(struct cmd_syndesc *syn, int pos, const char **str) +{ + *str = NULL; + if (pos > syn->nParms) return CMD_EXCESSPARMS; - if (syn->parms[pos].items == NULL || - syn->parms[pos].items->data == NULL) - return CMD_MISSING; + + /* It's a flag, they probably shouldn't be using this interface to access + * it, but don't blow up for now */ if (syn->parms[pos].items == &dummy) + return 0; + + /* We have a value on the command line - this overrides anything in the + * configuration file */ + if (syn->parms[pos].items != NULL && + syn->parms[pos].items->data != NULL) { + *str = syn->parms[pos].items->data; return 0; + } + + return _get_file_string(syn, pos, str); +} + +int +cmd_OptionAsInt(struct cmd_syndesc *syn, int pos, int *value) +{ + const char *str; + int code; + + code =_get_config_string(syn, pos, &str); + if (code) + return code; + + if (str == NULL) + return CMD_MISSING; - *value = strtol(syn->parms[pos].items->data, NULL, 10); + *value = strtol(str, NULL, 10); return 0; } @@ -1267,15 +1379,17 @@ int cmd_OptionAsUint(struct cmd_syndesc *syn, int pos, unsigned int *value) { - if (pos > syn->nParms) - return CMD_EXCESSPARMS; - if (syn->parms[pos].items == NULL || - syn->parms[pos].items->data == NULL) + const char *str; + int code; + + code = _get_config_string(syn, pos, &str); + if (code) + return code; + + if (str == NULL) return CMD_MISSING; - if (syn->parms[pos].items == &dummy) - return 0; - *value = strtoul(syn->parms[pos].items->data, NULL, 10); + *value = strtoul(str, NULL, 10); return 0; } @@ -1283,17 +1397,19 @@ cmd_OptionAsUint(struct cmd_syndesc *syn, int pos, int cmd_OptionAsString(struct cmd_syndesc *syn, int pos, char **value) { - if (pos > syn->nParms) - return CMD_EXCESSPARMS; - if (syn->parms[pos].items == NULL || syn->parms[pos].items->data == NULL) + const char *str; + int code; + + code = _get_config_string(syn, pos, &str); + if (code) + return code; + + if (str == NULL) return CMD_MISSING; - if (syn->parms[pos].items == &dummy) - return 0; if (*value) free(*value); - - *value = strdup(syn->parms[pos].items->data); + *value = strdup(str); return 0; } @@ -1301,32 +1417,118 @@ cmd_OptionAsString(struct cmd_syndesc *syn, int pos, char **value) int cmd_OptionAsList(struct cmd_syndesc *syn, int pos, struct cmd_item **value) { + const char *str; + struct cmd_item *item, **last; + const char *start, *end; + size_t len; + int code; + if (pos > syn->nParms) return CMD_EXCESSPARMS; - if (syn->parms[pos].items == NULL) - return CMD_MISSING; + + /* If we have a list already, just return the existing list */ + if (syn->parms[pos].items != NULL) { + *value = syn->parms[pos].items; + return 0; + } + + code = _get_file_string(syn, pos, &str); + if (code) + return code; + + /* Use strchr to split str into elements, and build a recursive list + * from them. Hang this list off the configuration structure, so that + * it is returned by any future calls to this function, and is freed + * along with everything else when the syntax description is freed + */ + last = &syn->parms[pos].items; + start = str; + while ((end = strchr(start, ' '))) { + item = calloc(1, sizeof(struct cmd_item)); + len = end - start + 1; + item->data = malloc(len); + strlcpy(item->data, start, len); + *last = item; + last = &item->next; + for (start = end; *start == ' '; start++); /* skip any whitespace */ + } + + /* Catch the final element */ + if (*start != '\0') { + item = calloc(1, sizeof(struct cmd_item)); + len = strlen(start) + 1; + item->data = malloc(len); + strlcpy(item->data, start, len); + *last = item; + } *value = syn->parms[pos].items; + return 0; } int cmd_OptionAsFlag(struct cmd_syndesc *syn, int pos, int *value) { - if (pos > syn->nParms) - return CMD_EXCESSPARMS; - if (syn->parms[pos].items == NULL) - return CMD_MISSING; + const char *str = NULL; + int code; + + code = _get_config_string(syn, pos, &str); + if (code) + return code; + + if (str == NULL || + strcasecmp(str, "yes") == 0 || + strcasecmp(str, "true") == 0 || + atoi(str)) + *value = 1; + else + *value = 0; - *value = 1; return 0; } int cmd_OptionPresent(struct cmd_syndesc *syn, int pos) { - if (pos > syn->nParms || syn->parms[pos].items == NULL) - return 0; + const char *str; + int code; - return 1; + code = _get_config_string(syn, pos, &str); + if (code == 0) + return 1; + + return 0; +} + +int +cmd_OpenConfigFile(const char *file) +{ + if (globalConfig) { + cmd_RawConfigFileFree(globalConfig); + globalConfig = NULL; + } + + return cmd_RawConfigParseFile(file, &globalConfig); +} + +void +cmd_SetCommandName(const char *command) +{ + commandName = command; +} + +const cmd_config_section * +cmd_RawFile(void) +{ + return globalConfig; +} + +const cmd_config_section * +cmd_RawSection(void) +{ + if (globalConfig == NULL || commandName == NULL) + return NULL; + + return cmd_RawConfigGetList(globalConfig, commandName, NULL); }