1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-31 21:18:26 +03:00
lvm2/scripts/create-commands.c
2016-09-06 16:30:00 -05:00

1535 lines
35 KiB
C

#include <asm/types.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdint.h>
#include <stdarg.h>
#include <limits.h>
#include <unistd.h>
#include <syslog.h>
#include <sched.h>
#include <dirent.h>
#include <ctype.h>
#include <getopt.h>
/* needed to include args.h */
#define ARG_COUNTABLE 0x00000001
#define ARG_GROUPABLE 0x00000002
struct cmd_context;
struct arg_values;
int yes_no_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
int activation_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
int cachemode_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
int discards_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
int mirrorlog_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
int size_kb_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
int size_mb_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
int size_mb_arg_with_percent(struct cmd_context *cmd, struct arg_values *av) { return 0; }
int int_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
int int_arg_with_sign(struct cmd_context *cmd, struct arg_values *av) { return 0; }
int int_arg_with_sign_and_percent(struct cmd_context *cmd, struct arg_values *av) { return 0; }
int major_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
int minor_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
int string_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
int tag_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
int permission_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
int metadatatype_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
int units_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
int segtype_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
int alloc_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
int locktype_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
int readahead_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
int metadatacopies_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av) { return 0; }
struct opt_name {
const char *enum_name;
int enum_val;
const char short_opt;
char _padding[7];
const char *long_opt;
/* NULL if option takes no arg */
int (*fn) (struct cmd_context *cmd, struct arg_values *av);
uint32_t unused1;
uint32_t unused2;
};
/* enum for opt names */
enum {
#define arg(a, b, c, d, e, f) a ,
#include "args.h"
#undef arg
};
static struct opt_name opt_names[ARG_COUNT + 1] = {
#define arg(a, b, c, d, e, f) { # a, a, b, "", "--" c, d, e, f},
#include "args.h"
#undef arg
};
#include "command.h"
#define MAX_CMD_NAMES 128
struct cmd_name {
const char *name;
};
static struct cmd_name cmd_names[MAX_CMD_NAMES] = {
#define xx(a, b...) { # a } ,
#include "commands.h"
#undef xx
};
#define MAX_LINE 1024
#define MAX_LINE_ARGC 256
#define REQUIRED 1
#define OPTIONAL 0
struct oo_line {
char *name;
char *line;
};
#define MAX_CMDS 256
int cmd_count;
struct command cmd_array[MAX_CMDS];
#define MAX_OO_LINES 256
int oo_line_count;
struct oo_line oo_lines[MAX_OO_LINES];
static void add_optional_opt_line(struct command *cmd, int argc, char *argv[]);
static int opt_str_to_num(char *str)
{
char long_name[32];
char *p;
int i;
/*
* --foo_long means there are two args entries
* for --foo, one with a short option and one
* without, and we want the one without the
* short option.
*/
if (strstr(str, "_long")) {
strcpy(long_name, str);
p = strstr(long_name, "_long");
*p = '\0';
for (i = 0; i < ARG_COUNT; i++) {
if (!opt_names[i].long_opt)
continue;
/* skip anything with a short opt */
if (opt_names[i].short_opt)
continue;
if (!strcmp(opt_names[i].long_opt, long_name))
return opt_names[i].enum_val;
}
printf("Unknown opt str: %s %s\n", str, long_name);
exit(1);
}
for (i = 0; i < ARG_COUNT; i++) {
if (!opt_names[i].long_opt)
continue;
/* These are only selected using --foo_long */
if (strstr(opt_names[i].enum_name, "_long_ARG"))
continue;
if (!strcmp(opt_names[i].long_opt, str))
return opt_names[i].enum_val;
}
printf("Unknown opt str: \"%s\"\n", str);
exit(1);
}
static int lv_str_to_num(char *str)
{
char name[32] = { 0 };
char *new;
int i;
/* compare the lv name before the _new suffix */
strncpy(name, str, 31);
if ((new = strstr(name, "_new")))
*new = '\0';
if (!strcmp(name, "LV"))
return 0;
for (i = 1; i < ARG_DEF_LVS; i++) {
if (!arg_def_lvs[i].name)
break;
if (!strcmp(name, arg_def_lvs[i].name))
return arg_def_lvs[i].flag;
}
printf("Unknown LV type: \"%s\" \"%s\"\n", name, str);
exit(1);
}
static int type_str_to_num(char *str)
{
char name[32] = { 0 };
char *new;
int i;
/* compare the name before the _new suffix */
strncpy(name, str, 31);
if ((new = strstr(name, "_new")))
*new = '\0';
for (i = 0; i < ARG_DEF_TYPES; i++) {
if (!arg_def_types[i].name)
break;
if (!strncmp(name, arg_def_types[i].name, strlen(arg_def_types[i].name)))
return arg_def_types[i].flag;
}
return 0;
}
/*
* modifies buf, replacing the sep characters with \0
* argv pointers point to positions in buf
*/
static char *split_line(char *buf, int *argc, char **argv, char sep)
{
char *p = buf, *rp = NULL;
int i;
argv[0] = p;
for (i = 1; i < MAX_LINE_ARGC; i++) {
p = strchr(buf, sep);
if (!p)
break;
*p = '\0';
argv[i] = p + 1;
buf = p + 1;
}
*argc = i;
/* we ended by hitting \0, return the point following that */
if (!rp)
rp = strchr(buf, '\0') + 1;
return rp;
}
static const char *is_command_name(char *str)
{
int i;
for (i = 0; i < MAX_CMD_NAMES; i++) {
if (!cmd_names[i].name)
break;
if (!strcmp(cmd_names[i].name, str))
return cmd_names[i].name;
}
return NULL;
}
static int is_opt_name(char *str)
{
if (!strncmp(str, "--", 2))
return 1;
if ((str[0] == '-') && (str[1] != '-')) {
printf("Options must be specified in long form: %s\n", str);
exit(1);
}
return 0;
}
/*
* "Select" as a pos name means that the position
* can be empty if the --select option is used.
*/
static int is_pos_name(char *str)
{
if (!strncmp(str, "VG", 2))
return 1;
if (!strncmp(str, "LV", 2))
return 1;
if (!strncmp(str, "PV", 2))
return 1;
if (!strncmp(str, "Tag", 3))
return 1;
if (!strncmp(str, "String", 6))
return 1;
if (!strncmp(str, "Select", 6))
return 1;
return 0;
}
static int is_oo_definition(char *str)
{
if (!strncmp(str, "OO_", 3))
return 1;
return 0;
}
static int is_oo_line(char *str)
{
if (!strncmp(str, "OO:", 3))
return 1;
return 0;
}
static int is_op_line(char *str)
{
if (!strncmp(str, "OP:", 3))
return 1;
return 0;
}
static int is_desc_line(char *str)
{
if (!strncmp(str, "DESC:", 5))
return 1;
return 0;
}
/*
* parse str for anything that can appear in a position,
* like VG, VG|LV, VG|LV_linear|LV_striped, etc
*/
static void set_pos_def(struct command *cmd, char *str, struct arg_def *def)
{
char *argv[MAX_LINE_ARGC];
int argc;
char *name;
int type_num;
int i;
split_line(str, &argc, argv, '|');
for (i = 0; i < argc; i++) {
name = argv[i];
type_num = type_str_to_num(name);
if (!type_num) {
printf("Unknown pos arg: %s\n", name);
exit(1);
}
def->types |= type_num;
if ((type_num == ARG_DEF_TYPE_NAME_LV) && strstr(name, "_"))
def->lv_types |= lv_str_to_num(name);
if (strstr(name, "_new"))
def->flags |= ARG_DEF_FLAG_NEW;
}
}
/*
* parse str for anything that can follow --option
*/
static void set_opt_def(struct command *cmd, char *str, struct arg_def *def)
{
char *argv[MAX_LINE_ARGC];
int argc;
char *name;
int type_num;
int i, j;
split_line(str, &argc, argv, '|');
for (i = 0; i < argc; i++) {
name = argv[i];
type_num = type_str_to_num(name);
if (!type_num) {
/* a literal number or string */
if (isdigit(name[0]))
type_num = ARG_DEF_TYPE_NUM_CONST;
else if (isalpha(name[0]))
type_num = ARG_DEF_TYPE_STR_CONST;
else {
printf("Unknown opt arg: %s\n", name);
exit(0);
}
}
switch (type_num) {
case ARG_DEF_TYPE_NONE:
break;
case ARG_DEF_TYPE_BOOL:
case ARG_DEF_TYPE_NUM_ANY:
case ARG_DEF_TYPE_STR_ANY:
case ARG_DEF_TYPE_NAME_ANY:
case ARG_DEF_TYPE_NAME_PV:
case ARG_DEF_TYPE_NAME_VG:
case ARG_DEF_TYPE_TAG:
def->types |= type_num;
break;
case ARG_DEF_TYPE_NUM_CONST:
def->types |= type_num;
def->num = (uint64_t)atoi(name);
break;
case ARG_DEF_TYPE_STR_CONST:
if (def->types & ARG_DEF_TYPE_STR_CONST) {
def->types &= ~ARG_DEF_TYPE_STR_CONST;
def->types |= ARG_DEF_TYPE_STR_SET;
def->str_set[0] = def->str;
def->str = NULL;
}
if (def->types & ARG_DEF_TYPE_STR_SET) {
for (j = 0; j < MAX_STR_SET; j++) {
if (def->str_set[j])
continue;
def->str_set[j] = strdup(name);
break;
}
} else {
def->types |= type_num;
def->str = strdup(name);
}
break;
case ARG_DEF_TYPE_NAME_LV:
def->types |= type_num;
if (strstr(name, "_"))
def->lv_types |= lv_str_to_num(name);
break;
}
if ((type_num == ARG_DEF_TYPE_NAME_VG) ||
(type_num == ARG_DEF_TYPE_NAME_LV) ||
(type_num == ARG_DEF_TYPE_NAME_PV)) {
if (strstr(name, "_new"))
def->flags |= ARG_DEF_FLAG_NEW;
}
}
}
/*
* OO_FOO: --opt1 ...
*
* oo->name = "OO_FOO";
* oo->line = "--opt1 ...";
*/
static void add_oo_definition_line(const char *name, const char *line)
{
struct oo_line *oo;
char *colon;
char *start;
oo = &oo_lines[oo_line_count++];
oo->name = strdup(name);
if ((colon = strstr(oo->name, ":")))
*colon = '\0';
else {
printf("invalid OO definition\n");
exit(1);
}
start = strstr(line, ":") + 2;
oo->line = strdup(start);
}
/* when OO_FOO: continues on multiple lines */
static void append_oo_definition_line(const char *new_line)
{
struct oo_line *oo;
char *old_line;
char *line;
int len;
oo = &oo_lines[oo_line_count-1];
old_line = oo->line;
/* +2 = 1 space between old and new + 1 terminating \0 */
len = strlen(old_line) + strlen(new_line) + 2;
line = malloc(len);
memset(line, 0, len);
strcat(line, old_line);
strcat(line, " ");
strcat(line, new_line);
free(oo->line);
oo->line = line;
}
char *get_oo_line(char *str)
{
char *name;
char *end;
char str2[64];
int i;
strcpy(str2, str);
if ((end = strstr(str2, ":")))
*end = '\0';
if ((end = strstr(str2, ",")))
*end = '\0';
for (i = 0; i < oo_line_count; i++) {
name = oo_lines[i].name;
if (!strcmp(name, str2))
return oo_lines[i].line;
}
return NULL;
}
/* add optional_opt_args entries when OO_FOO appears on OO: line */
static void include_optional_opt_args(struct command *cmd, char *str)
{
char *oo_line;
char *line;
char *line_argv[MAX_LINE_ARGC];
int line_argc;
if (!(oo_line = get_oo_line(str))) {
printf("No OO line found for %s\n", str);
exit(1);
}
if (!(line = strdup(oo_line)))
exit(1);
split_line(line, &line_argc, line_argv, ' ');
add_optional_opt_line(cmd, line_argc, line_argv);
free(line);
}
static void add_opt_arg(struct command *cmd, char *str, int *takes_arg, int required)
{
char *comma;
int opt;
/* opt_arg.opt set here */
/* opt_arg.def will be set in update_prev_opt_arg() if needed */
if ((comma = strstr(str, ",")))
*comma = '\0';
/*
* Work around nasty hack where --uuid is used for both uuid_ARG
* and uuidstr_ARG. The input uses --uuidstr, where an actual
* command uses --uuid string.
*/
if (!strcmp(str, "--uuidstr")) {
opt = uuidstr_ARG;
goto skip;
}
opt = opt_str_to_num(str);
skip:
if (required)
cmd->required_opt_args[cmd->ro_count++].opt = opt;
else
cmd->optional_opt_args[cmd->oo_count++].opt = opt;
*takes_arg = opt_names[opt].fn ? 1 : 0;
}
static void update_prev_opt_arg(struct command *cmd, char *str, int required)
{
struct arg_def def = { 0 };
char *comma;
if (str[0] == '-') {
printf("Option %s must be followed by an arg.\n", str);
exit(1);
}
/* opt_arg.def set here */
/* opt_arg.opt was previously set in add_opt_arg() when --foo was read */
if ((comma = strstr(str, ",")))
*comma = '\0';
set_opt_def(cmd, str, &def);
if (required)
cmd->required_opt_args[cmd->ro_count-1].def = def;
else
cmd->optional_opt_args[cmd->oo_count-1].def = def;
}
static void add_pos_arg(struct command *cmd, char *str, int required)
{
struct arg_def def = { 0 };
/* pos_arg.pos and pos_arg.def are set here */
set_pos_def(cmd, str, &def);
if (required) {
cmd->required_pos_args[cmd->rp_count].pos = cmd->pos_count++;
cmd->required_pos_args[cmd->rp_count].def = def;
cmd->rp_count++;
} else {
cmd->optional_pos_args[cmd->op_count].pos = cmd->pos_count++;;
cmd->optional_pos_args[cmd->op_count].def = def;
cmd->op_count++;
}
}
/* process something that follows a pos arg, which is not a new pos arg */
static void update_prev_pos_arg(struct command *cmd, char *str, int required)
{
struct arg_def *def;
/* a previous pos_arg.def is modified here */
if (required)
def = &cmd->required_pos_args[cmd->rp_count-1].def;
else
def = &cmd->optional_pos_args[cmd->op_count-1].def;
if (!strcmp(str, "..."))
def->flags |= ARG_DEF_FLAG_MAY_REPEAT;
else {
printf("Unknown pos arg: %s\n", str);
exit(1);
}
}
/* process what follows OO:, which are optional opt args */
static void add_optional_opt_line(struct command *cmd, int argc, char *argv[])
{
int takes_arg;
int i;
for (i = 0; i < argc; i++) {
if (!i && !strncmp(argv[i], "OO:", 3))
continue;
if (is_opt_name(argv[i]))
add_opt_arg(cmd, argv[i], &takes_arg, OPTIONAL);
else if (!strncmp(argv[i], "OO_", 3))
include_optional_opt_args(cmd, argv[i]);
else if (takes_arg)
update_prev_opt_arg(cmd, argv[i], OPTIONAL);
else
printf("Can't parse argc %d argv %s prev %s\n",
i, argv[i], argv[i-1]);
}
}
/* process what follows OP:, which are optional pos args */
static void add_optional_pos_line(struct command *cmd, int argc, char *argv[])
{
int i;
for (i = 0; i < argc; i++) {
if (!i && !strncmp(argv[i], "OP:", 3))
continue;
if (is_pos_name(argv[i]))
add_pos_arg(cmd, argv[i], OPTIONAL);
else
update_prev_pos_arg(cmd, argv[i], OPTIONAL);
}
}
/* add required opt args from OO_FOO definition */
static void add_required_opt_line(struct command *cmd, int argc, char *argv[])
{
int takes_arg;
int i;
for (i = 0; i < argc; i++) {
if (is_opt_name(argv[i]))
add_opt_arg(cmd, argv[i], &takes_arg, REQUIRED);
else if (takes_arg)
update_prev_opt_arg(cmd, argv[i], REQUIRED);
else
printf("Can't parse argc %d argv %s prev %s\n",
i, argv[i], argv[i-1]);
}
}
/* add to required_opt_args when OO_FOO appears on required line */
static void include_required_opt_args(struct command *cmd, char *str)
{
char *oo_line;
char *line;
char *line_argv[MAX_LINE_ARGC];
int line_argc;
if (!(oo_line = get_oo_line(str))) {
printf("No OO line found for %s\n", str);
exit(1);
}
if (!(line = strdup(oo_line)))
exit(1);
split_line(line, &line_argc, line_argv, ' ');
add_required_opt_line(cmd, line_argc, line_argv);
free(line);
}
/* process what follows command_name, which are required opt/pos args */
static void add_required_line(struct command *cmd, int argc, char *argv[])
{
int i;
int takes_arg;
int prev_was_opt = 0, prev_was_pos = 0;
/* argv[0] is command name */
for (i = 1; i < argc; i++) {
if (is_opt_name(argv[i])) {
add_opt_arg(cmd, argv[i], &takes_arg, REQUIRED);
prev_was_opt = 1;
prev_was_pos = 0;
} else if (prev_was_opt && takes_arg) {
update_prev_opt_arg(cmd, argv[i], REQUIRED);
prev_was_opt = 0;
prev_was_pos = 0;
} else if (is_pos_name(argv[i])) {
add_pos_arg(cmd, argv[i], REQUIRED);
prev_was_opt = 0;
prev_was_pos = 1;
} else if (!strncmp(argv[i], "OO_", 3)) {
cmd->cmd_flags |= CMD_FLAG_ONE_REQUIRED_OPT;
include_required_opt_args(cmd, argv[i]);
} else if (prev_was_pos) {
update_prev_pos_arg(cmd, argv[i], REQUIRED);
} else
printf("Can't parse argc %d argv %s prev %s\n",
i, argv[i], argv[i-1]);
}
}
static void print_def(struct arg_def *def)
{
int sep = 0;
int i;
if (def->types & ARG_DEF_TYPE_BOOL) {
if (sep) printf("|");
printf("Bool");
sep = 1;
}
if (def->types & ARG_DEF_TYPE_NUM_ANY) {
if (sep) printf("|");
printf("Number");
sep = 1;
}
if (def->types & ARG_DEF_TYPE_STR_ANY) {
if (sep) printf("|");
printf("String");
sep = 1;
}
if (def->types & ARG_DEF_TYPE_NAME_ANY) {
if (sep) printf("|");
printf("Name");
sep = 1;
}
if (def->types & ARG_DEF_TYPE_NAME_PV) {
if (sep) printf("|");
printf("PV");
if (def->flags & ARG_DEF_FLAG_NEW)
printf("_new");
sep = 1;
}
if (def->types & ARG_DEF_TYPE_NAME_VG) {
if (sep) printf("|");
printf("VG");
if (def->flags & ARG_DEF_FLAG_NEW)
printf("_new");
sep = 1;
}
if (def->types & ARG_DEF_TYPE_NAME_LV) {
if (!def->lv_types) {
if (sep) printf("|");
printf("LV");
sep = 1;
} else {
for (i = 0; i < ARG_DEF_LVS; i++) {
if (def->lv_types & arg_def_lvs[i].flag) {
if (sep) printf("|");
printf("%s", arg_def_lvs[i].name);
sep = 1;
}
}
}
if (def->flags & ARG_DEF_FLAG_NEW)
printf("_new");
}
if (def->types & ARG_DEF_TYPE_TAG) {
if (sep) printf("|");
printf("Tag");
sep = 1;
}
if (def->types & ARG_DEF_TYPE_SELECT) {
if (sep) printf("|");
printf("Select");
sep = 1;
}
if (def->types & ARG_DEF_TYPE_STR_CONST) {
if (sep) printf("|");
printf("%s", def->str);
sep = 1;
}
if (def->types & ARG_DEF_TYPE_NUM_CONST) {
if (sep) printf("|");
printf("%llu", def->num);
sep = 1;
}
if (def->types & ARG_DEF_TYPE_STR_SET) {
for (i = 0; i < MAX_STR_SET; i++) {
if (def->str_set[i]) {
if (sep) printf("|");
printf("%s", def->str_set[i]);
sep = 1;
}
}
}
if (def->flags & ARG_DEF_FLAG_MAY_REPEAT)
printf(" ...");
}
void print_data_expanded(void)
{
struct command *cmd;
int i, ro, rp, oo, op;
for (i = 0; i < cmd_count; i++) {
cmd = &cmd_array[i];
printf("%s", cmd->name);
if (cmd->ro_count) {
for (ro = 0; ro < cmd->ro_count; ro++) {
printf(" %s", opt_names[cmd->required_opt_args[ro].opt].long_opt);
if (cmd->required_opt_args[ro].def.types) {
printf(" ");
print_def(&cmd->required_opt_args[ro].def);
}
}
}
if (cmd->rp_count) {
for (rp = 0; rp < cmd->rp_count; rp++) {
if (cmd->required_pos_args[rp].def.types) {
printf(" ");
print_def(&cmd->required_pos_args[rp].def);
}
}
}
if (cmd->oo_count) {
printf("\n");
printf("OO:");
for (oo = 0; oo < cmd->oo_count; oo++) {
if (oo)
printf(",");
printf(" %s", opt_names[cmd->optional_opt_args[oo].opt].long_opt);
if (cmd->optional_opt_args[oo].def.types) {
printf(" ");
print_def(&cmd->optional_opt_args[oo].def);
}
}
}
if (cmd->op_count) {
printf("\n");
printf("OP:");
for (op = 0; op < cmd->op_count; op++) {
if (cmd->optional_pos_args[op].def.types) {
printf(" ");
print_def(&cmd->optional_pos_args[op].def);
}
}
}
printf("\n\n");
}
}
static const char *opt_to_enum_str(int opt)
{
return opt_names[opt].enum_name;
}
static char *type_num_to_flags(int types)
{
static char buf[128];
int or = 0;
memset(buf, 0, sizeof(buf));
if (types & ARG_DEF_TYPE_BOOL) {
strcat(buf, "ARG_DEF_TYPE_BOOL");
or = 1;
}
if (types & ARG_DEF_TYPE_NUM_ANY) {
if (or) strcat(buf, "|");
strcat(buf, "ARG_DEF_TYPE_NUM_ANY");
or = 1;
}
if (types & ARG_DEF_TYPE_STR_ANY) {
if (or) strcat(buf, "|");
strcat(buf, "ARG_DEF_TYPE_STR_ANY");
or = 1;
}
if (types & ARG_DEF_TYPE_NUM_CONST) {
if (or) strcat(buf, "|");
strcat(buf, "ARG_DEF_TYPE_NUM_CONST");
or = 1;
}
if (types & ARG_DEF_TYPE_STR_CONST) {
if (or) strcat(buf, "|");
strcat(buf, "ARG_DEF_TYPE_STR_CONST");
or = 1;
}
if (types & ARG_DEF_TYPE_STR_SET) {
if (or) strcat(buf, "|");
strcat(buf, "ARG_DEF_TYPE_STR_SET");
or = 1;
}
if (types & ARG_DEF_TYPE_NAME_ANY) {
if (or) strcat(buf, "|");
strcat(buf, "ARG_DEF_TYPE_NAME_ANY");
or = 1;
}
if (types & ARG_DEF_TYPE_NAME_PV) {
if (or) strcat(buf, "|");
strcat(buf, "ARG_DEF_TYPE_NAME_PV");
or = 1;
}
if (types & ARG_DEF_TYPE_NAME_VG) {
if (or) strcat(buf, "|");
strcat(buf, "ARG_DEF_TYPE_NAME_VG");
or = 1;
}
if (types & ARG_DEF_TYPE_NAME_LV) {
if (or) strcat(buf, "|");
strcat(buf, "ARG_DEF_TYPE_NAME_LV");
or = 1;
}
if (types & ARG_DEF_TYPE_TAG) {
if (or) strcat(buf, "|");
strcat(buf, "ARG_DEF_TYPE_TAG");
or = 1;
}
if (types & ARG_DEF_TYPE_SELECT) {
if (or) strcat(buf, "|");
strcat(buf, "ARG_DEF_TYPE_SELECT");
or = 1;
}
return buf;
}
static char *lv_num_to_flags(int lv_types)
{
static char buf_lv_types[128];
int or = 0;
memset(buf_lv_types, 0, sizeof(buf_lv_types));
if (lv_types & ARG_DEF_LV_LINEAR) {
if (or) strcat(buf_lv_types, "|");
strcat(buf_lv_types, "ARG_DEF_LV_LINEAR");
or = 1;
}
if (lv_types & ARG_DEF_LV_STRIPED) {
if (or) strcat(buf_lv_types, "|");
strcat(buf_lv_types, "ARG_DEF_LV_STRIPED");
or = 1;
}
if (lv_types & ARG_DEF_LV_SNAPSHOT) {
if (or) strcat(buf_lv_types, "|");
strcat(buf_lv_types, "ARG_DEF_LV_SNAPSHOT");
or = 1;
}
if (lv_types & ARG_DEF_LV_MIRROR) {
if (or) strcat(buf_lv_types, "|");
strcat(buf_lv_types, "ARG_DEF_LV_MIRROR");
or = 1;
}
if (lv_types & ARG_DEF_LV_RAID) {
if (or) strcat(buf_lv_types, "|");
strcat(buf_lv_types, "ARG_DEF_LV_RAID");
or = 1;
}
if (lv_types & ARG_DEF_LV_RAID0) {
if (or) strcat(buf_lv_types, "|");
strcat(buf_lv_types, "ARG_DEF_LV_RAID0");
or = 1;
}
if (lv_types & ARG_DEF_LV_RAID1) {
if (or) strcat(buf_lv_types, "|");
strcat(buf_lv_types, "ARG_DEF_LV_RAID1");
or = 1;
}
if (lv_types & ARG_DEF_LV_RAID4) {
if (or) strcat(buf_lv_types, "|");
strcat(buf_lv_types, "ARG_DEF_LV_RAID4");
or = 1;
}
if (lv_types & ARG_DEF_LV_RAID5) {
if (or) strcat(buf_lv_types, "|");
strcat(buf_lv_types, "ARG_DEF_LV_RAID5");
or = 1;
}
if (lv_types & ARG_DEF_LV_RAID6) {
if (or) strcat(buf_lv_types, "|");
strcat(buf_lv_types, "ARG_DEF_LV_RAID6");
or = 1;
}
if (lv_types & ARG_DEF_LV_RAID10) {
if (or) strcat(buf_lv_types, "|");
strcat(buf_lv_types, "ARG_DEF_LV_RAID10");
or = 1;
}
if (lv_types & ARG_DEF_LV_THIN) {
if (or) strcat(buf_lv_types, "|");
strcat(buf_lv_types, "ARG_DEF_LV_THIN");
or = 1;
}
if (lv_types & ARG_DEF_LV_THINPOOL) {
if (or) strcat(buf_lv_types, "|");
strcat(buf_lv_types, "ARG_DEF_LV_THINPOOL");
or = 1;
}
if (lv_types & ARG_DEF_LV_CACHE) {
if (or) strcat(buf_lv_types, "|");
strcat(buf_lv_types, "ARG_DEF_LV_CACHE");
or = 1;
}
if (lv_types & ARG_DEF_LV_CACHEPOOL) {
if (or) strcat(buf_lv_types, "|");
strcat(buf_lv_types, "ARG_DEF_LV_CACHEPOOL");
or = 1;
}
return buf_lv_types;
}
static char *flags_to_str(int flags)
{
static char buf_flags[32];
memset(buf_flags, 0, sizeof(buf_flags));
if (flags & ARG_DEF_FLAG_MAY_REPEAT)
strcat(buf_flags, "ARG_DEF_FLAG_MAY_REPEAT");
if (flags & ARG_DEF_FLAG_NEW)
strcat(buf_flags, "ARG_DEF_FLAG_NEW");
return buf_flags;
}
void print_define_command_count(void)
{
printf("#define COMMAND_COUNT %d\n", cmd_count);
}
void print_usage(struct command *cmd)
{
int onereq = (cmd->cmd_flags & CMD_FLAG_ONE_REQUIRED_OPT) ? 1 : 0;
int i, ro, rp, oo, op;
printf("\"%s", cmd->name);
if (cmd->ro_count) {
if (onereq)
printf(" (");
for (ro = 0; ro < cmd->ro_count; ro++) {
if (ro && onereq)
printf(",");
printf(" %s", opt_names[cmd->required_opt_args[ro].opt].long_opt);
if (cmd->required_opt_args[ro].def.types) {
printf(" ");
print_def(&cmd->required_opt_args[ro].def);
}
}
if (onereq)
printf(" )");
}
if (cmd->rp_count) {
for (rp = 0; rp < cmd->rp_count; rp++) {
if (cmd->required_pos_args[rp].def.types) {
printf(" ");
print_def(&cmd->required_pos_args[rp].def);
}
}
}
printf("\"");
if (!cmd->oo_count)
goto op_count;
printf("\n");
printf("\"[");
if (cmd->oo_count) {
for (oo = 0; oo < cmd->oo_count; oo++) {
if (oo)
printf(",");
printf(" %s", opt_names[cmd->optional_opt_args[oo].opt].long_opt);
if (cmd->optional_opt_args[oo].def.types) {
printf(" ");
print_def(&cmd->optional_opt_args[oo].def);
}
}
}
printf(" ]\"");
op_count:
if (!cmd->op_count)
goto done;
printf("\n");
printf("\"[");
if (cmd->op_count) {
for (op = 0; op < cmd->op_count; op++) {
if (cmd->optional_pos_args[op].def.types) {
printf(" ");
print_def(&cmd->optional_pos_args[op].def);
}
}
}
printf(" ]\"");
done:
printf(";\n");
}
void print_command_count(void)
{
printf("#define COMMAND_COUNT %d\n", cmd_count);
}
void print_command_structs(void)
{
struct command *cmd;
int i, j, ro, rp, oo, op;
for (i = 0; i < cmd_count; i++) {
cmd = &cmd_array[i];
printf("commands[%d].name = \"%s\";\n", i, cmd->name);
printf("commands[%d].fn = %s;\n", i, cmd->name);
printf("commands[%d].desc = \"%s\";\n", i, cmd->desc ?: "");
printf("commands[%d].usage = ", i);
print_usage(cmd);
if (cmd->ro_count) {
for (ro = 0; ro < cmd->ro_count; ro++) {
printf("commands[%d].required_opt_args[%d].opt = %s;\n",
i, ro, opt_to_enum_str(cmd->required_opt_args[ro].opt));
if (!cmd->required_opt_args[ro].def.types)
continue;
printf("commands[%d].required_opt_args[%d].def.types = %s;\n",
i, ro, type_num_to_flags(cmd->required_opt_args[ro].def.types));
if (cmd->required_opt_args[ro].def.lv_types)
printf("commands[%d].required_opt_args[%d].def.lv_types = %s;\n",
i, ro, lv_num_to_flags(cmd->required_opt_args[ro].def.lv_types));
if (cmd->required_opt_args[ro].def.types & ARG_DEF_TYPE_NUM_CONST)
printf("commands[%d].required_opt_args[%d].def.num = %d;\n",
i, ro, cmd->required_opt_args[ro].def.num);
if (cmd->required_opt_args[ro].def.flags)
printf("commands[%d].required_opt_args[%d].def.flags = %s;\n",
i, ro, flags_to_str(cmd->required_opt_args[ro].def.flags));
if (cmd->required_opt_args[ro].def.types & ARG_DEF_TYPE_STR_CONST)
printf("commands[%d].required_opt_args[%d].def.str = \"%s\";\n",
i, ro, cmd->required_opt_args[ro].def.str ?: "NULL");
if (cmd->required_opt_args[ro].def.types & ARG_DEF_TYPE_STR_SET) {
for (j = 0; j < MAX_STR_SET; j++) {
if (cmd->required_opt_args[ro].def.str_set[j])
printf("commands[%d].required_opt_args[%d].def.str_set[%d] = %s;\n",
i, ro, j, cmd->required_opt_args[ro].def.str_set[j] ?: "NULL");
}
}
}
}
if (cmd->rp_count) {
for (rp = 0; rp < cmd->rp_count; rp++) {
printf("commands[%d].required_pos_args[%d].pos = %d;\n",
i, rp, cmd->required_pos_args[rp].pos);
if (!cmd->required_pos_args[rp].def.types)
continue;
printf("commands[%d].required_pos_args[%d].def.types = %s;\n",
i, rp, type_num_to_flags(cmd->required_pos_args[rp].def.types));
if (cmd->required_pos_args[rp].def.lv_types)
printf("commands[%d].required_pos_args[%d].def.lv_types = %s;\n",
i, rp, lv_num_to_flags(cmd->required_pos_args[rp].def.lv_types));
if (cmd->required_pos_args[rp].def.types & ARG_DEF_TYPE_NUM_CONST)
printf("commands[%d].required_pos_args[%d].def.num = %d;\n",
i, rp, cmd->required_pos_args[rp].def.num);
if (cmd->required_pos_args[rp].def.flags)
printf("commands[%d].required_pos_args[%d].def.flags = %s;\n",
i, rp, flags_to_str(cmd->required_pos_args[rp].def.flags));
if (cmd->required_pos_args[rp].def.types & ARG_DEF_TYPE_STR_CONST)
printf("commands[%d].required_pos_args[%d].def.str = \"%s\";\n",
i, rp, cmd->required_pos_args[rp].def.str ?: "NULL");
if (cmd->required_pos_args[rp].def.types & ARG_DEF_TYPE_STR_SET) {
for (j = 0; j < MAX_STR_SET; j++) {
if (cmd->required_pos_args[rp].def.str_set[j])
printf("commands[%d].required_pos_args[%d].def.str_set[%d] = \"%s\";\n",
i, rp, j, cmd->required_pos_args[rp].def.str_set[j] ?: "NULL");
}
}
}
}
if (cmd->oo_count) {
for (oo = 0; oo < cmd->oo_count; oo++) {
printf("commands[%d].optional_opt_args[%d].opt = %s;\n",
i, oo, opt_to_enum_str(cmd->optional_opt_args[oo].opt));
if (!cmd->optional_opt_args[oo].def.types)
continue;
printf("commands[%d].optional_opt_args[%d].def.types = %s;\n",
i, oo, type_num_to_flags(cmd->optional_opt_args[oo].def.types));
if (cmd->optional_opt_args[oo].def.lv_types)
printf("commands[%d].optional_opt_args[%d].def.lv_types = %s;\n",
i, oo, lv_num_to_flags(cmd->optional_opt_args[oo].def.lv_types));
if (cmd->optional_opt_args[oo].def.types & ARG_DEF_TYPE_NUM_CONST)
printf("commands[%d].optional_opt_args[%d].def.num = %d;\n",
i, oo, cmd->optional_opt_args[oo].def.num);
if (cmd->optional_opt_args[oo].def.flags)
printf("commands[%d].optional_opt_args[%d].def.flags = %s;\n",
i, oo, flags_to_str(cmd->optional_opt_args[oo].def.flags));
if (cmd->optional_opt_args[oo].def.types & ARG_DEF_TYPE_STR_CONST)
printf("commands[%d].optional_opt_args[%d].def.str = \"%s\";\n",
i, oo, cmd->optional_opt_args[oo].def.str ?: "NULL");
if (cmd->optional_opt_args[oo].def.types & ARG_DEF_TYPE_STR_SET) {
for (j = 0; j < MAX_STR_SET; j++) {
if (cmd->optional_opt_args[oo].def.str_set[j])
printf("commands[%d].optional_opt_args[%d].def.str_set[%d] = \"%s\";\n",
i, oo, j, cmd->optional_opt_args[oo].def.str_set[j] ?: "NULL");
}
}
}
}
if (cmd->op_count) {
for (op = 0; op < cmd->op_count; op++) {
printf("commands[%d].optional_pos_args[%d].pos = %d;\n",
i, op, cmd->optional_pos_args[op].pos);
if (!cmd->optional_pos_args[op].def.types)
continue;
printf("commands[%d].optional_pos_args[%d].def.types = %s;\n",
i, op, type_num_to_flags(cmd->optional_pos_args[op].def.types));
if (cmd->optional_pos_args[op].def.lv_types)
printf("commands[%d].optional_pos_args[%d].def.lv_types = %s;\n",
i, op, lv_num_to_flags(cmd->optional_pos_args[op].def.lv_types));
if (cmd->optional_pos_args[op].def.types & ARG_DEF_TYPE_NUM_CONST)
printf("commands[%d].optional_pos_args[%d].def.num = %d;\n",
i, op, cmd->optional_pos_args[op].def.num);
if (cmd->optional_pos_args[op].def.flags)
printf("commands[%d].optional_pos_args[%d].def.flags = %s;\n",
i, op, flags_to_str(cmd->optional_pos_args[op].def.flags));
if (cmd->optional_pos_args[op].def.types & ARG_DEF_TYPE_STR_CONST)
printf("commands[%d].optional_pos_args[%d].def.str = \"%s\";\n",
i, op, cmd->optional_pos_args[op].def.str ?: "NULL");
if (cmd->optional_pos_args[op].def.types & ARG_DEF_TYPE_STR_SET) {
for (j = 0; j < MAX_STR_SET; j++) {
if (cmd->optional_pos_args[op].def.str_set[j])
printf("commands[%d].optional_pos_args[%d].def.str_set[%d] = \"%s\";\n",
i, op, j, cmd->optional_pos_args[op].def.str_set[j] ?: "NULL");
}
}
}
}
printf("\n");
}
}
void print_command_list(void)
{
int i;
for (i = 0; i < MAX_CMD_NAMES; i++) {
if (!cmd_names[i].name) {
printf("found %d command names\n", i);
break;
}
printf("%s\n", cmd_names[i].name);
}
}
void print_option_list(void)
{
int i;
for (i = 0; i < ARG_COUNT; i++)
printf("%d %s %s %c\n",
opt_names[i].enum_val, opt_names[i].enum_name,
opt_names[i].long_opt, opt_names[i].short_opt ?: ' ');
}
static void print_help(int argc, char *argv[])
{
printf("%s --output struct|count|expand <filename>\n", argv[0]);
printf("\n");
printf("struct: print C structures for command definitions.\n");
printf("expand: print expanded input format.\n");
printf("count: print #define COMMAND_COUNT <Number>\n");
}
int main(int argc, char *argv[])
{
char *outputformat = NULL;
char *inputfile = NULL;
FILE *file;
struct command *cmd;
char line[MAX_LINE];
char line_orig[MAX_LINE];
const char *name;
char *line_argv[MAX_LINE_ARGC];
char *n;
int line_argc;
int prev_was_oo_def = 0;
int prev_was_oo = 0;
int prev_was_op = 0;
if (argc < 2) {
print_help(argc, argv);
exit(EXIT_FAILURE);
}
static struct option long_options[] = {
{"help", no_argument, 0, 'h' },
{"output", required_argument, 0, 'o' },
{0, 0, 0, 0 }
};
while (1) {
int c;
int option_index = 0;
c = getopt_long(argc, argv, "ho:",
long_options, &option_index);
if (c == -1)
break;
switch (c) {
case '0':
break;
case 'h':
print_help(argc, argv);
exit(EXIT_SUCCESS);
case 'o':
outputformat = strdup(optarg);
break;
}
}
if (optind < argc)
inputfile = argv[optind];
else {
printf("Missing filename.\n");
return 0;
}
if (!(file = fopen(inputfile, "r"))) {
printf("Cannot open %s\n", argv[1]);
return -1;
}
while (fgets(line, MAX_LINE, file)) {
if (line[0] == '#')
continue;
if (line[0] == '\n')
continue;
if ((n = strchr(line, '\n')))
*n = '\0';
memcpy(line_orig, line, sizeof(line));
split_line(line, &line_argc, line_argv, ' ');
if (!line_argc)
continue;
/* command ... */
if ((name = is_command_name(line_argv[0]))) {
if (cmd_count >= MAX_CMDS) {
printf("MAX_CMDS too small\n");
return -1;
}
cmd = &cmd_array[cmd_count++];
cmd->name = name;
cmd->pos_count = 1;
add_required_line(cmd, line_argc, line_argv);
/* Every cmd gets the OO_ALL options */
include_optional_opt_args(cmd, "OO_ALL:");
continue;
}
if (is_desc_line(line_argv[0])) {
char *desc = strdup(strstr(line_orig, ":") + 2);
if (cmd->desc) {
cmd->desc = realloc((char *)cmd->desc, strlen(cmd->desc) + strlen(desc) + 2);
strcat((char *)cmd->desc, "\n");
strcat((char *)cmd->desc, desc);
free(desc);
} else
cmd->desc = desc;
continue;
}
/* OO_FOO: ... */
if (is_oo_definition(line_argv[0])) {
add_oo_definition_line(line_argv[0], line_orig);
prev_was_oo_def = 1;
prev_was_oo = 0;
prev_was_op = 0;
continue;
}
/* OO: ... */
if (is_oo_line(line_argv[0])) {
add_optional_opt_line(cmd, line_argc, line_argv);
prev_was_oo_def = 0;
prev_was_oo = 1;
prev_was_op = 0;
continue;
}
/* OP: ... */
if (is_op_line(line_argv[0])) {
add_optional_pos_line(cmd, line_argc, line_argv);
prev_was_oo_def = 0;
prev_was_oo = 0;
prev_was_op = 1;
continue;
}
/* handle OO_FOO:, OO:, OP: continuing on multiple lines */
if (prev_was_oo_def) {
append_oo_definition_line(line_orig);
continue;
}
if (prev_was_oo) {
add_optional_opt_line(cmd, line_argc, line_argv);
continue;
}
if (prev_was_op) {
add_optional_pos_line(cmd, line_argc, line_argv);
continue;
}
}
fclose(file);
if (!outputformat)
print_data_expanded();
else if (!strcmp(outputformat, "struct"))
print_command_structs();
else if (!strcmp(outputformat, "count"))
print_command_count();
else if (!strcmp(outputformat, "expand"))
print_data_expanded();
else
print_help(argc, argv);
}