* [PATCH v3 2/4] kvm tool: Mostly the copied code from perf for argument processing
2011-04-08 15:11 [PATCH v3 1/4] kvm tool: Generating list of common kvm tool commands Prasad Joshi
@ 2011-04-08 15:11 ` Prasad Joshi
2011-04-08 15:11 ` [PATCH v3 3/4] kvm tool: Provides the basic Gitish framework Prasad Joshi
2011-04-08 15:11 ` [PATCH v3 4/4] kvm tool: Using the Gitish freamwork to run the virtual machine Prasad Joshi
2 siblings, 0 replies; 4+ messages in thread
From: Prasad Joshi @ 2011-04-08 15:11 UTC (permalink / raw)
To: prasadjoshi124
Cc: mingo, kvm, penberg, asias.hejun, gorcunov, oswaldo.cadenas
- parse-options.[ch] has argument processing code.
- types.h: Additional types for argument processing.
- strbuf.[ch]: Added a function prefixcmp to compare string prefix
Signed-off-by: Prasad Joshi <prasadjoshi124@gmail.com>
---
tools/kvm/include/kvm/parse-options.h | 161 +++++++++
tools/kvm/include/kvm/strbuf.h | 6 +
tools/kvm/include/kvm/util.h | 8 +
tools/kvm/include/linux/types.h | 12 +
tools/kvm/util/parse-options.c | 570 +++++++++++++++++++++++++++++++++
tools/kvm/util/strbuf.c | 13 +
6 files changed, 770 insertions(+), 0 deletions(-)
create mode 100644 tools/kvm/include/kvm/parse-options.h
create mode 100644 tools/kvm/include/kvm/strbuf.h
create mode 100644 tools/kvm/util/parse-options.c
create mode 100644 tools/kvm/util/strbuf.c
diff --git a/tools/kvm/include/kvm/parse-options.h b/tools/kvm/include/kvm/parse-options.h
new file mode 100644
index 0000000..b59220d
--- /dev/null
+++ b/tools/kvm/include/kvm/parse-options.h
@@ -0,0 +1,161 @@
+#ifndef __PARSE_OPTIONS_H__
+#define __PARSE_OPTIONS_H__
+
+enum parse_opt_type {
+ /* special types */
+ OPTION_END,
+ OPTION_ARGUMENT,
+ OPTION_GROUP,
+ /* options with no arguments */
+ OPTION_BIT,
+ OPTION_BOOLEAN,
+ OPTION_INCR,
+ OPTION_SET_UINT,
+ OPTION_SET_PTR,
+ /* options with arguments (usually) */
+ OPTION_STRING,
+ OPTION_INTEGER,
+ OPTION_LONG,
+ OPTION_CALLBACK,
+ OPTION_U64,
+ OPTION_UINTEGER,
+};
+
+enum parse_opt_flags {
+ PARSE_OPT_KEEP_DASHDASH = 1,
+ PARSE_OPT_STOP_AT_NON_OPTION = 2,
+ PARSE_OPT_KEEP_ARGV0 = 4,
+ PARSE_OPT_KEEP_UNKNOWN = 8,
+ PARSE_OPT_NO_INTERNAL_HELP = 16,
+};
+
+enum parse_opt_option_flags {
+ PARSE_OPT_OPTARG = 1,
+ PARSE_OPT_NOARG = 2,
+ PARSE_OPT_NONEG = 4,
+ PARSE_OPT_HIDDEN = 8,
+ PARSE_OPT_LASTARG_DEFAULT = 16,
+};
+
+struct option;
+typedef int parse_opt_cb(const struct option *, const char *arg, int unset);
+/*
+ * `type`::
+ * holds the type of the option, you must have an OPTION_END last in your
+ * array.
+ *
+ * `short_name`::
+ * the character to use as a short option name, '\0' if none.
+ *
+ * `long_name`::
+ * the long option name, without the leading dashes, NULL if none.
+ *
+ * `value`::
+ * stores pointers to the values to be filled.
+ *
+ * `argh`::
+ * token to explain the kind of argument this option wants. Keep it
+ * homogenous across the repository.
+ *
+ * `help`::
+ * the short help associated to what the option does.
+ * Must never be NULL (except for OPTION_END).
+ * OPTION_GROUP uses this pointer to store the group header.
+ *
+ * `flags`::
+ * mask of parse_opt_option_flags.
+ * PARSE_OPT_OPTARG: says that the argument is optionnal (not for BOOLEANs)
+ * PARSE_OPT_NOARG: says that this option takes no argument, for CALLBACKs
+ * PARSE_OPT_NONEG: says that this option cannot be negated
+ * PARSE_OPT_HIDDEN this option is skipped in the default usage, showed in
+ * the long one.
+ *
+ * `callback`::
+ * pointer to the callback to use for OPTION_CALLBACK.
+ *
+ * `defval`::
+ * default value to fill (*->value) with for PARSE_OPT_OPTARG.
+ * OPTION_{BIT,SET_UINT,SET_PTR} store the {mask,integer,pointer} to put in
+ * the value when met.
+ * CALLBACKS can use it like they want.
+ */
+struct option {
+enum parse_opt_type type;
+int short_name;
+const char *long_name;
+void *value;
+const char *argh;
+const char *help;
+
+int flags;
+parse_opt_cb *callback;
+intptr_t defval;
+};
+
+#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))
+#define check_vtype(v, type) \
+ (BUILD_BUG_ON_ZERO(!__builtin_types_compatible_p(typeof(v), type)) + v)
+
+#define OPT_INTEGER(s, l, v, h) \
+{ \
+ .type = OPTION_INTEGER, \
+ .short_name = (s), \
+ .long_name = (l), \
+ .value = check_vtype(v, int *), \
+ .help = (h) \
+}
+
+#define OPT_U64(s, l, v, h) \
+{ \
+ .type = OPTION_U64, \
+ .short_name = (s), \
+ .long_name = (l), \
+ .value = check_vtype(v, u64 *), \
+ .help = (h) \
+}
+
+#define OPT_STRING(s, l, v, a, h) \
+{ \
+ .type = OPTION_STRING, \
+ .short_name = (s), \
+ .long_name = (l), \
+ .value = check_vtype(v, const char **), (a), \
+ .help = (h) \
+}
+
+#define OPT_BOOLEAN(s, l, v, h) \
+{ \
+ .type = OPTION_BOOLEAN, \
+ .short_name = (s), \
+ .long_name = (l), \
+ .value = check_vtype(v, bool *), \
+ .help = (h) \
+}
+
+#define OPT_END() { .type = OPTION_END }
+
+enum {
+ PARSE_OPT_HELP = -1,
+ PARSE_OPT_DONE,
+ PARSE_OPT_UNKNOWN,
+};
+
+/*
+ * It's okay for the caller to consume argv/argc in the usual way.
+ * Other fields of that structure are private to parse-options and should not
+ * be modified in any way.
+ **/
+struct parse_opt_ctx_t {
+ const char **argv;
+ const char **out;
+ int argc, cpidx;
+ const char *opt;
+ int flags;
+};
+
+/* global functions */
+void usage_with_options(const char * const *usagestr,
+ const struct option *opts);
+int parse_options(int argc, const char **argv, const struct option *options,
+ const char * const usagestr[], int flags);
+#endif
diff --git a/tools/kvm/include/kvm/strbuf.h b/tools/kvm/include/kvm/strbuf.h
new file mode 100644
index 0000000..e67ca20
--- /dev/null
+++ b/tools/kvm/include/kvm/strbuf.h
@@ -0,0 +1,6 @@
+#ifndef __STRBUF_H__
+#define __STRBUF_H__
+
+int prefixcmp(const char *str, const char *prefix);
+
+#endif
diff --git a/tools/kvm/include/kvm/util.h b/tools/kvm/include/kvm/util.h
index 8c80777..ae033cc 100644
--- a/tools/kvm/include/kvm/util.h
+++ b/tools/kvm/include/kvm/util.h
@@ -48,4 +48,12 @@ do { \
extern size_t strlcat(char *dest, const char *src, size_t count);
+/* some inline functions */
+
+static inline const char *skip_prefix(const char *str, const char *prefix)
+{
+ size_t len = strlen(prefix);
+ return strncmp(str, prefix, len) ? NULL : str + len;
+}
+
#endif /* KVM__UTIL_H */
diff --git a/tools/kvm/include/linux/types.h b/tools/kvm/include/linux/types.h
index 70e2546..b989d2a 100644
--- a/tools/kvm/include/linux/types.h
+++ b/tools/kvm/include/linux/types.h
@@ -15,4 +15,16 @@
#define __s64 int64_t
#define __u64 uint64_t
+typedef __u64 u64;
+typedef __s64 s64;
+
+typedef __u32 u32;
+typedef __s32 s32;
+
+typedef __u16 u16;
+typedef __s16 s16;
+
+typedef __u8 u8;
+typedef __s8 s8;
+
#endif /* LINUX_TYPES_H */
diff --git a/tools/kvm/util/parse-options.c b/tools/kvm/util/parse-options.c
new file mode 100644
index 0000000..94edf7b
--- /dev/null
+++ b/tools/kvm/util/parse-options.c
@@ -0,0 +1,570 @@
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdint.h>
+
+#include <stdbool.h>
+
+/* user defined includes */
+#include <linux/types.h>
+#include <kvm/util.h>
+#include <kvm/parse-options.h>
+#include <kvm/strbuf.h>
+
+#define OPT_SHORT 1
+#define OPT_UNSET 2
+
+static int opterror(const struct option *opt, const char *reason, int flags)
+{
+ if (flags & OPT_SHORT)
+ return error("switch `%c' %s", opt->short_name, reason);
+ if (flags & OPT_UNSET)
+ return error("option `no-%s' %s", opt->long_name, reason);
+ return error("option `%s' %s", opt->long_name, reason);
+}
+
+static int get_arg(struct parse_opt_ctx_t *p, const struct option *opt,
+ int flags, const char **arg)
+{
+ if (p->opt) {
+ *arg = p->opt;
+ p->opt = NULL;
+ } else if ((opt->flags & PARSE_OPT_LASTARG_DEFAULT) && (p->argc == 1 ||
+ **(p->argv + 1) == '-')) {
+ *arg = (const char *)opt->defval;
+ } else if (p->argc > 1) {
+ p->argc--;
+ *arg = *++p->argv;
+ } else
+ return opterror(opt, "requires a value", flags);
+ return 0;
+}
+
+static int get_value(struct parse_opt_ctx_t *p,
+ const struct option *opt, int flags)
+{
+ const char *s, *arg = NULL;
+ const int unset = flags & OPT_UNSET;
+
+ if (unset && p->opt)
+ return opterror(opt, "takes no value", flags);
+ if (unset && (opt->flags & PARSE_OPT_NONEG))
+ return opterror(opt, "isn't available", flags);
+
+ if (!(flags & OPT_SHORT) && p->opt) {
+ switch (opt->type) {
+ case OPTION_CALLBACK:
+ if (!(opt->flags & PARSE_OPT_NOARG))
+ break;
+ /* FALLTHROUGH */
+ case OPTION_BOOLEAN:
+ case OPTION_INCR:
+ case OPTION_BIT:
+ case OPTION_SET_UINT:
+ case OPTION_SET_PTR:
+ return opterror(opt, "takes no value", flags);
+ case OPTION_END:
+ case OPTION_ARGUMENT:
+ case OPTION_GROUP:
+ case OPTION_STRING:
+ case OPTION_INTEGER:
+ case OPTION_UINTEGER:
+ case OPTION_LONG:
+ case OPTION_U64:
+ default:
+ break;
+ }
+ }
+
+ switch (opt->type) {
+ case OPTION_BIT:
+ if (unset)
+ *(int *)opt->value &= ~opt->defval;
+ else
+ *(int *)opt->value |= opt->defval;
+ return 0;
+
+ case OPTION_BOOLEAN:
+ *(bool *)opt->value = unset ? false : true;
+ return 0;
+
+ case OPTION_INCR:
+ *(int *)opt->value = unset ? 0 : *(int *)opt->value + 1;
+ return 0;
+
+ case OPTION_SET_UINT:
+ *(unsigned int *)opt->value = unset ? 0 : opt->defval;
+ return 0;
+
+ case OPTION_SET_PTR:
+ *(void **)opt->value = unset ? NULL : (void *)opt->defval;
+ return 0;
+
+ case OPTION_STRING:
+ if (unset)
+ *(const char **)opt->value = NULL;
+ else if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
+ *(const char **)opt->value = (const char *)opt->defval;
+ else
+ return get_arg(p, opt, flags,
+ (const char **)opt->value);
+ return 0;
+
+ case OPTION_CALLBACK:
+ if (unset)
+ return (*opt->callback)(opt, NULL, 1) ? (-1) : 0;
+ if (opt->flags & PARSE_OPT_NOARG)
+ return (*opt->callback)(opt, NULL, 0) ? (-1) : 0;
+ if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
+ return (*opt->callback)(opt, NULL, 0) ? (-1) : 0;
+ if (get_arg(p, opt, flags, &arg))
+ return -1;
+ return (*opt->callback)(opt, arg, 0) ? (-1) : 0;
+
+ case OPTION_INTEGER:
+ if (unset) {
+ *(int *)opt->value = 0;
+ return 0;
+ }
+ if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
+ *(int *)opt->value = opt->defval;
+ return 0;
+ }
+ if (get_arg(p, opt, flags, &arg))
+ return -1;
+ *(int *)opt->value = strtol(arg, (char **)&s, 10);
+ if (*s)
+ return opterror(opt, "expects a numerical value",
+ flags);
+ return 0;
+
+ case OPTION_UINTEGER:
+ if (unset) {
+ *(unsigned int *)opt->value = 0;
+ return 0;
+ }
+ if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
+ *(unsigned int *)opt->value = opt->defval;
+ return 0;
+ }
+ if (get_arg(p, opt, flags, &arg))
+ return -1;
+ *(unsigned int *)opt->value = strtol(arg, (char **)&s, 10);
+ if (*s)
+ return opterror(opt,
+ "expects a numerical value", flags);
+ return 0;
+
+ case OPTION_LONG:
+ if (unset) {
+ *(long *)opt->value = 0;
+ return 0;
+ }
+ if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
+ *(long *)opt->value = opt->defval;
+ return 0;
+ }
+ if (get_arg(p, opt, flags, &arg))
+ return -1;
+ *(long *)opt->value = strtol(arg, (char **)&s, 10);
+ if (*s)
+ return opterror(opt,
+ "expects a numerical value", flags);
+ return 0;
+
+ case OPTION_U64:
+ if (unset) {
+ *(u64 *)opt->value = 0;
+ return 0;
+ }
+ if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
+ *(u64 *)opt->value = opt->defval;
+ return 0;
+ }
+ if (get_arg(p, opt, flags, &arg))
+ return -1;
+ *(u64 *)opt->value = strtoull(arg, (char **)&s, 10);
+ if (*s)
+ return opterror(opt,
+ "expects a numerical value", flags);
+ return 0;
+
+ case OPTION_END:
+ case OPTION_ARGUMENT:
+ case OPTION_GROUP:
+ default:
+ die("should not happen, someone must be hit on the forehead");
+ }
+}
+
+#define USAGE_OPTS_WIDTH 24
+#define USAGE_GAP 2
+
+static int usage_with_options_internal(const char * const *usagestr,
+ const struct option *opts, int full)
+{
+ if (!usagestr)
+ return PARSE_OPT_HELP;
+
+ fprintf(stderr, "\n usage: %s\n", *usagestr++);
+ while (*usagestr && **usagestr)
+ fprintf(stderr, " or: %s\n", *usagestr++);
+ while (*usagestr) {
+ fprintf(stderr, "%s%s\n",
+ **usagestr ? " " : "",
+ *usagestr);
+ usagestr++;
+ }
+
+ if (opts->type != OPTION_GROUP)
+ fputc('\n', stderr);
+
+ for (; opts->type != OPTION_END; opts++) {
+ size_t pos;
+ int pad;
+
+ if (opts->type == OPTION_GROUP) {
+ fputc('\n', stderr);
+ if (*opts->help)
+ fprintf(stderr, "%s\n", opts->help);
+ continue;
+ }
+ if (!full && (opts->flags & PARSE_OPT_HIDDEN))
+ continue;
+
+ pos = fprintf(stderr, " ");
+ if (opts->short_name)
+ pos += fprintf(stderr, "-%c", opts->short_name);
+ else
+ pos += fprintf(stderr, " ");
+
+ if (opts->long_name && opts->short_name)
+ pos += fprintf(stderr, ", ");
+ if (opts->long_name)
+ pos += fprintf(stderr, "--%s", opts->long_name);
+
+ switch (opts->type) {
+ case OPTION_ARGUMENT:
+ break;
+ case OPTION_LONG:
+ case OPTION_U64:
+ case OPTION_INTEGER:
+ case OPTION_UINTEGER:
+ if (opts->flags & PARSE_OPT_OPTARG)
+ if (opts->long_name)
+ pos += fprintf(stderr, "[=<n>]");
+ else
+ pos += fprintf(stderr, "[<n>]");
+ else
+ pos += fprintf(stderr, " <n>");
+ break;
+ case OPTION_CALLBACK:
+ if (opts->flags & PARSE_OPT_NOARG)
+ break;
+ /* FALLTHROUGH */
+ case OPTION_STRING:
+ if (opts->argh) {
+ if (opts->flags & PARSE_OPT_OPTARG)
+ if (opts->long_name)
+ pos += fprintf(stderr, "[=<%s>]", opts->argh);
+ else
+ pos += fprintf(stderr, "[<%s>]", opts->argh);
+ else
+ pos += fprintf(stderr, " <%s>", opts->argh);
+ } else {
+ if (opts->flags & PARSE_OPT_OPTARG)
+ if (opts->long_name)
+ pos += fprintf(stderr, "[=...]");
+ else
+ pos += fprintf(stderr, "[...]");
+ else
+ pos += fprintf(stderr, " ...");
+ }
+ break;
+ default: /* OPTION_{BIT,BOOLEAN,SET_UINT,SET_PTR} */
+ case OPTION_END:
+ case OPTION_GROUP:
+ case OPTION_BIT:
+ case OPTION_BOOLEAN:
+ case OPTION_INCR:
+ case OPTION_SET_UINT:
+ case OPTION_SET_PTR:
+ break;
+ }
+ if (pos <= USAGE_OPTS_WIDTH)
+ pad = USAGE_OPTS_WIDTH - pos;
+ else {
+ fputc('\n', stderr);
+ pad = USAGE_OPTS_WIDTH;
+ }
+ fprintf(stderr, "%*s%s\n", pad + USAGE_GAP, "", opts->help);
+ }
+ fputc('\n', stderr);
+
+ return PARSE_OPT_HELP;
+}
+
+void usage_with_options(const char * const *usagestr,
+ const struct option *opts)
+{
+ usage_with_options_internal(usagestr, opts, 0);
+ exit(129);
+}
+
+static void check_typos(const char *arg, const struct option *options)
+{
+ if (strlen(arg) < 3)
+ return;
+
+ if (!prefixcmp(arg, "no-")) {
+ error ("did you mean `--%s` (with two dashes ?)", arg);
+ exit(129);
+ }
+
+ for (; options->type != OPTION_END; options++) {
+ if (!options->long_name)
+ continue;
+ if (!prefixcmp(options->long_name, arg)) {
+ error ("did you mean `--%s` (with two dashes ?)", arg);
+ exit(129);
+ }
+ }
+}
+
+static int parse_options_usage(const char * const *usagestr,
+ const struct option *opts)
+{
+ return usage_with_options_internal(usagestr, opts, 0);
+}
+
+static int parse_short_opt(struct parse_opt_ctx_t *p,
+ const struct option *options)
+{
+ for (; options->type != OPTION_END; options++) {
+ if (options->short_name == *p->opt) {
+ p->opt = p->opt[1] ? p->opt + 1 : NULL;
+ return get_value(p, options, OPT_SHORT);
+ }
+ }
+ return -2;
+}
+
+static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg,
+ const struct option *options)
+{
+ const char *arg_end = strchr(arg, '=');
+ const struct option *abbrev_option = NULL, *ambiguous_option = NULL;
+ int abbrev_flags = 0, ambiguous_flags = 0;
+
+ if (!arg_end)
+ arg_end = arg + strlen(arg);
+
+ for (; options->type != OPTION_END; options++) {
+ const char *rest;
+ int flags = 0;
+
+ if (!options->long_name)
+ continue;
+
+ rest = skip_prefix(arg, options->long_name);
+ if (options->type == OPTION_ARGUMENT) {
+ if (!rest)
+ continue;
+ if (*rest == '=')
+ return opterror(options, "takes no value",
+ flags);
+ if (*rest)
+ continue;
+ p->out[p->cpidx++] = arg - 2;
+ return 0;
+ }
+ if (!rest) {
+ /* abbreviated? */
+ if (!strncmp(options->long_name, arg, arg_end - arg)) {
+is_abbreviated:
+ if (abbrev_option) {
+ /*
+ * If this is abbreviated, it is
+ * ambiguous. So when there is no
+ * exact match later, we need to
+ * error out.
+ */
+ ambiguous_option = abbrev_option;
+ ambiguous_flags = abbrev_flags;
+ }
+ if (!(flags & OPT_UNSET) && *arg_end)
+ p->opt = arg_end + 1;
+ abbrev_option = options;
+ abbrev_flags = flags;
+ continue;
+ }
+ /* negated and abbreviated very much? */
+ if (!prefixcmp("no-", arg)) {
+ flags |= OPT_UNSET;
+ goto is_abbreviated;
+ }
+ /* negated? */
+ if (strncmp(arg, "no-", 3))
+ continue;
+ flags |= OPT_UNSET;
+ rest = skip_prefix(arg + 3, options->long_name);
+ /* abbreviated and negated? */
+ if (!rest && !prefixcmp(options->long_name, arg + 3))
+ goto is_abbreviated;
+ if (!rest)
+ continue;
+ }
+ if (*rest) {
+ if (*rest != '=')
+ continue;
+ p->opt = rest + 1;
+ }
+ return get_value(p, options, flags);
+ }
+
+ if (ambiguous_option)
+ return error("Ambiguous option: %s "
+ "(could be --%s%s or --%s%s)",
+ arg,
+ (ambiguous_flags & OPT_UNSET) ? "no-" : "",
+ ambiguous_option->long_name,
+ (abbrev_flags & OPT_UNSET) ? "no-" : "",
+ abbrev_option->long_name);
+ if (abbrev_option)
+ return get_value(p, abbrev_option, abbrev_flags);
+ return -2;
+}
+
+
+static void parse_options_start(struct parse_opt_ctx_t *ctx, int argc,
+ const char **argv, int flags)
+{
+ memset(ctx, 0, sizeof(*ctx));
+ ctx->argc = argc;
+ ctx->argv = argv;
+ ctx->out = argv;
+ ctx->cpidx = ((flags & PARSE_OPT_KEEP_ARGV0) != 0);
+ ctx->flags = flags;
+ if ((flags & PARSE_OPT_KEEP_UNKNOWN) &&
+ (flags & PARSE_OPT_STOP_AT_NON_OPTION))
+ die("STOP_AT_NON_OPTION and KEEP_UNKNOWN don't go together");
+}
+
+static int parse_options_end(struct parse_opt_ctx_t *ctx)
+{
+ memmove(ctx->out + ctx->cpidx, ctx->argv, ctx->argc * sizeof(*ctx->out));
+ ctx->out[ctx->cpidx + ctx->argc] = NULL;
+ return ctx->cpidx + ctx->argc;
+}
+
+
+static int parse_options_step(struct parse_opt_ctx_t *ctx,
+ const struct option *options, const char * const usagestr[])
+{
+ int internal_help = !(ctx->flags & PARSE_OPT_NO_INTERNAL_HELP);
+
+ /* we must reset ->opt, unknown short option leave it dangling */
+ ctx->opt = NULL;
+
+ for (; ctx->argc; ctx->argc--, ctx->argv++) {
+ const char *arg = ctx->argv[0];
+
+ if (*arg != '-' || !arg[1]) {
+ if (ctx->flags & PARSE_OPT_STOP_AT_NON_OPTION)
+ break;
+ ctx->out[ctx->cpidx++] = ctx->argv[0];
+ continue;
+ }
+
+ if (arg[1] != '-') {
+ ctx->opt = arg + 1;
+ if (internal_help && *ctx->opt == 'h')
+ return parse_options_usage(usagestr, options);
+ switch (parse_short_opt(ctx, options)) {
+ case -1:
+ return parse_options_usage(usagestr, options);
+ case -2:
+ goto unknown;
+ default:
+ break;
+ }
+ if (ctx->opt)
+ check_typos(arg + 1, options);
+ while (ctx->opt) {
+ if (internal_help && *ctx->opt == 'h')
+ return parse_options_usage(usagestr,
+ options);
+ switch (parse_short_opt(ctx, options)) {
+ case -1:
+ return parse_options_usage(usagestr,
+ options);
+ case -2:
+ /* fake a short option thing to hide
+ * the fact that we may have
+ * started to parse aggregated stuff
+ *
+ * This is leaky, too bad.
+ */
+ ctx->argv[0] = strdup(ctx->opt - 1);
+ *(char *)ctx->argv[0] = '-';
+ goto unknown;
+ default:
+ break;
+ }
+ }
+ continue;
+ }
+
+ if (!arg[2]) { /* "--" */
+ if (!(ctx->flags & PARSE_OPT_KEEP_DASHDASH)) {
+ ctx->argc--;
+ ctx->argv++;
+ }
+ break;
+ }
+
+ if (internal_help && !strcmp(arg + 2, "help-all"))
+ return usage_with_options_internal(usagestr, options,
+ 1);
+ if (internal_help && !strcmp(arg + 2, "help"))
+ return parse_options_usage(usagestr, options);
+ switch (parse_long_opt(ctx, arg + 2, options)) {
+ case -1:
+ return parse_options_usage(usagestr, options);
+ case -2:
+ goto unknown;
+ default:
+ break;
+ }
+ continue;
+unknown:
+ if (!(ctx->flags & PARSE_OPT_KEEP_UNKNOWN))
+ return PARSE_OPT_UNKNOWN;
+ ctx->out[ctx->cpidx++] = ctx->argv[0];
+ ctx->opt = NULL;
+ }
+ return PARSE_OPT_DONE;
+}
+
+int parse_options(int argc, const char **argv, const struct option *options,
+ const char * const usagestr[], int flags)
+{
+ struct parse_opt_ctx_t ctx;
+
+ parse_options_start(&ctx, argc, argv, flags);
+ switch (parse_options_step(&ctx, options, usagestr)) {
+ case PARSE_OPT_HELP:
+ exit(129);
+ case PARSE_OPT_DONE:
+ break;
+ default: /* PARSE_OPT_UNKNOWN */
+ if (ctx.argv[0][1] == '-') {
+ error("unknown option `%s'", ctx.argv[0] + 2);
+ } else {
+ error("unknown switch `%c'", *ctx.opt);
+ }
+ usage_with_options(usagestr, options);
+ }
+
+ return parse_options_end(&ctx);
+}
diff --git a/tools/kvm/util/strbuf.c b/tools/kvm/util/strbuf.c
new file mode 100644
index 0000000..ec77ab1
--- /dev/null
+++ b/tools/kvm/util/strbuf.c
@@ -0,0 +1,13 @@
+
+/* user defined headers */
+#include <kvm/strbuf.h>
+
+int prefixcmp(const char *str, const char *prefix)
+{
+ for (; ; str++, prefix++) {
+ if (!*prefix)
+ return 0;
+ else if (*str != *prefix)
+ return (unsigned char)*prefix - (unsigned char)*str;
+ }
+}
--
1.7.1
^ permalink raw reply related [flat|nested] 4+ messages in thread* [PATCH v3 4/4] kvm tool: Using the Gitish freamwork to run the virtual machine
2011-04-08 15:11 [PATCH v3 1/4] kvm tool: Generating list of common kvm tool commands Prasad Joshi
2011-04-08 15:11 ` [PATCH v3 2/4] kvm tool: Mostly the copied code from perf for argument processing Prasad Joshi
2011-04-08 15:11 ` [PATCH v3 3/4] kvm tool: Provides the basic Gitish framework Prasad Joshi
@ 2011-04-08 15:11 ` Prasad Joshi
2 siblings, 0 replies; 4+ messages in thread
From: Prasad Joshi @ 2011-04-08 15:11 UTC (permalink / raw)
To: prasadjoshi124
Cc: mingo, kvm, penberg, asias.hejun, gorcunov, oswaldo.cadenas
- kvm-run.[ch] Adds a new kvm command called 'run'. The most of the code is
copied from main.c.
- main.c is modified to use the functionality provided by framework.
The old code from main.c is moved to kvm-run.c.
Signed-off-by: Prasad Joshi <prasadjoshi124@gmail.com>
---
tools/kvm/Makefile | 21 ++++-
tools/kvm/include/kvm/kvm-run.h | 6 +
tools/kvm/kvm-run.c | 224 +++++++++++++++++++++++++++++++++++++++
tools/kvm/main.c | 223 ++------------------------------------
4 files changed, 261 insertions(+), 213 deletions(-)
create mode 100644 tools/kvm/include/kvm/kvm-run.h
create mode 100644 tools/kvm/kvm-run.c
diff --git a/tools/kvm/Makefile b/tools/kvm/Makefile
index 55f342d..37e6ae5 100644
--- a/tools/kvm/Makefile
+++ b/tools/kvm/Makefile
@@ -26,6 +26,11 @@ OBJS += mmio.o
OBJS += pci.o
OBJS += util.o
OBJS += term.o
+OBJS += util/parse-options.o
+OBJS += util/strbuf.o
+OBJS += kvm-help.o
+OBJS += kvm-cmd.o
+OBJS += kvm-run.o
DEPS := $(patsubst %.o,%.d,$(OBJS))
@@ -55,7 +60,8 @@ endif
DEFINES += -D_FILE_OFFSET_BITS=64
DEFINES += -D_GNU_SOURCE
-CFLAGS += $(CPPFLAGS) $(DEFINES) -Iinclude -I../../include -I../../arch/$(ARCH)/include/ -Os -g
+KVM_INCLUDE := include
+CFLAGS += $(CPPFLAGS) $(DEFINES) -I$(KVM_INCLUDE) -I../../include -I../../arch/$(ARCH)/include/ -Os -g
WARNINGS += -Werror
WARNINGS += -Wall
@@ -87,12 +93,22 @@ $(DEPS):
%.d: %.c
$(Q) $(CC) -M -MT $(patsubst %.d,%.o,$@) $(CFLAGS) $< -o $@
+# The header file common-cmds.h is needed for compilation of kvm-help.c.
+kvm-help.d: $(KVM_INCLUDE)/common-cmds.h
+
$(OBJS):
%.o: %.c
$(E) " CC " $@
$(Q) $(CC) -c $(CFLAGS) $< -o $@
+
+$(KVM_INCLUDE)/common-cmds.h: util/generate-cmdlist.sh command-list.txt
+
+$(KVM_INCLUDE)/common-cmds.h: $(wildcard Documentation/kvm-*.txt)
+ $(E) " GEN " $@
+ $(Q) util/generate-cmdlist.sh > $@+ && mv $@+ $@
+
#
# BIOS assembly weirdness
#
@@ -118,7 +134,7 @@ bios/bios-rom.bin: bios/bios-rom.S bios/e820.c
check: $(PROGRAM)
$(MAKE) -C tests
- ./$(PROGRAM) tests/pit/tick.bin
+ ./$(PROGRAM) run --kernel=tests/pit/tick.bin
.PHONY: check
clean:
@@ -129,6 +145,7 @@ clean:
$(Q) rm -f bios/bios-rom.h
$(Q) rm -f $(DEPS) $(OBJS) $(PROGRAM)
$(Q) rm -f cscope.*
+ $(Q) rm -f $(KVM_INCLUDE)/common-cmds.h
.PHONY: clean
KVM_DEV ?= /dev/kvm
diff --git a/tools/kvm/include/kvm/kvm-run.h b/tools/kvm/include/kvm/kvm-run.h
new file mode 100644
index 0000000..13104e2
--- /dev/null
+++ b/tools/kvm/include/kvm/kvm-run.h
@@ -0,0 +1,6 @@
+#ifndef __KVM_RUN_H__
+#define __KVM_RUN_H__
+
+int kvm_cmd_run(int argc, const char **argv, const char *prefix);
+
+#endif
diff --git a/tools/kvm/kvm-run.c b/tools/kvm/kvm-run.c
new file mode 100644
index 0000000..f797a4e
--- /dev/null
+++ b/tools/kvm/kvm-run.c
@@ -0,0 +1,224 @@
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <termios.h>
+
+/* user defined header files */
+#include <linux/types.h>
+#include <kvm/kvm.h>
+#include <kvm/8250-serial.h>
+#include <kvm/blk-virtio.h>
+#include <kvm/console-virtio.h>
+#include <kvm/disk-image.h>
+#include <kvm/util.h>
+#include <kvm/pci.h>
+#include <kvm/term.h>
+
+/* header files for gitish interface */
+#include <kvm/kvm-run.h>
+#include <kvm/parse-options.h>
+
+#define DEFAULT_KVM_DEV "/dev/kvm"
+
+#define MB_SHIFT (20)
+#define MIN_RAM_SIZE_MB (64UL)
+#define MIN_RAM_SIZE_BYTE (MIN_RAM_SIZE_MB << MB_SHIFT)
+
+static struct kvm *kvm;
+
+static void handle_sigint(int sig)
+{
+ exit(1);
+}
+
+static void handle_sigquit(int sig)
+{
+ kvm__show_registers(kvm);
+ kvm__show_code(kvm);
+ kvm__show_page_tables(kvm);
+
+ kvm__delete(kvm);
+
+ exit(1);
+}
+
+static u64 ram_size;
+static const char *kernel_cmdline;
+static const char *kernel_filename;
+static const char *initrd_filename;
+static const char *image_filename;
+static const char *kvm_dev;
+static bool single_step = false;
+static bool virtio_console = false;
+extern bool ioport_debug;
+extern int active_console;
+
+static const char * const run_usage[] = {
+ "kvm run [<options>]",
+ NULL
+};
+
+static const struct option options[] = {
+ OPT_U64('m', "mem", &ram_size, "Virtual machine memory size in MiB."),
+ OPT_STRING('p', "params", &kernel_cmdline, "params",
+ "Kernel command line arguments"),
+ OPT_STRING('r', "initrd", &initrd_filename, "initrd",
+ "Initial RAM disk image"),
+ OPT_STRING('k', "kernel", &kernel_filename, "kernel",
+ "Kernel to boot in virtual machine"),
+ OPT_STRING('i', "image", &image_filename, "image", "Disk image"),
+ OPT_STRING('d', "kvm-dev", &kvm_dev, "kvm-dev", "KVM device file"),
+ OPT_BOOLEAN('s', "single-step", &single_step,
+ "Enable single stepping"),
+ OPT_BOOLEAN('g', "ioport-debug", &ioport_debug,
+ "Enable ioport debugging"),
+ OPT_BOOLEAN('c', "enable-virtio-console", &virtio_console,
+ "Enable the virtual IO console"),
+ OPT_END()
+};
+
+int kvm_cmd_run(int argc, const char **argv, const char *prefix)
+{
+ static char real_cmdline[2048];
+
+ signal(SIGQUIT, handle_sigquit);
+ signal(SIGINT, handle_sigint);
+
+ argc = parse_options(argc, argv, options, run_usage,
+ PARSE_OPT_STOP_AT_NON_OPTION);
+
+ if (!kernel_filename || !*kernel_filename) {
+ fprintf(stderr, "Please specify the --kernel option.\n");
+ usage_with_options(run_usage, options);
+ }
+
+ if (!ram_size)
+ ram_size = MIN_RAM_SIZE_MB;
+ else if (ram_size < MIN_RAM_SIZE_MB) {
+ die("Not enough memory specified: %luMB (min %luMB)", ram_size,
+ MIN_RAM_SIZE_MB);
+ }
+ ram_size <<= MB_SHIFT;
+
+ if (!kvm_dev)
+ kvm_dev = DEFAULT_KVM_DEV;
+
+ if (virtio_console == true)
+ active_console = CONSOLE_VIRTIO;
+
+ term_init();
+
+ kvm = kvm__init(kvm_dev, ram_size);
+
+ if (image_filename) {
+ kvm->disk_image = disk_image__open(image_filename);
+ if (!kvm->disk_image)
+ die("unable to load disk image %s", image_filename);
+ }
+
+ kvm__setup_cpuid(kvm);
+
+ strcpy(real_cmdline, "notsc nolapic noacpi pci=conf1 console=ttyS0 ");
+ if (!kernel_cmdline || !strstr(kernel_cmdline, "root=")) {
+ strlcat(real_cmdline, "root=/dev/vda rw ",
+ sizeof(real_cmdline));
+ }
+
+ if (kernel_cmdline) {
+ strlcat(real_cmdline, kernel_cmdline, sizeof(real_cmdline));
+ real_cmdline[sizeof(real_cmdline)-1] = '\0';
+ }
+
+ if (!kvm__load_kernel(kvm, kernel_filename, initrd_filename,
+ real_cmdline))
+ die("unable to load kernel %s", kernel_filename);
+
+ kvm__reset_vcpu(kvm);
+
+ kvm__setup_bios(kvm);
+
+ if (single_step)
+ kvm__enable_singlestep(kvm);
+
+ serial8250__init(kvm);
+
+ pci__init();
+
+ blk_virtio__init(kvm);
+
+ virtio_console__init(kvm);
+
+ kvm__start_timer(kvm);
+
+ for (;;) {
+ kvm__run(kvm);
+
+ switch (kvm->kvm_run->exit_reason) {
+ case KVM_EXIT_DEBUG:
+ kvm__show_registers(kvm);
+ kvm__show_code(kvm);
+ break;
+ case KVM_EXIT_IO: {
+ bool ret;
+
+ ret = kvm__emulate_io(kvm,
+ kvm->kvm_run->io.port,
+ (uint8_t *)kvm->kvm_run +
+ kvm->kvm_run->io.data_offset,
+ kvm->kvm_run->io.direction,
+ kvm->kvm_run->io.size,
+ kvm->kvm_run->io.count);
+
+ if (!ret)
+ goto panic_kvm;
+ break;
+ }
+ case KVM_EXIT_MMIO: {
+ bool ret;
+
+ ret = kvm__emulate_mmio(kvm,
+ kvm->kvm_run->mmio.phys_addr,
+ kvm->kvm_run->mmio.data,
+ kvm->kvm_run->mmio.len,
+ kvm->kvm_run->mmio.is_write);
+
+ if (!ret)
+ goto panic_kvm;
+ break;
+ }
+ case KVM_EXIT_INTR: {
+ serial8250__inject_interrupt(kvm);
+ virtio_console__inject_interrupt(kvm);
+ break;
+ }
+ case KVM_EXIT_SHUTDOWN:
+ goto exit_kvm;
+ default:
+ goto panic_kvm;
+ }
+ }
+exit_kvm:
+ disk_image__close(kvm->disk_image);
+ kvm__delete(kvm);
+
+ return 0;
+
+panic_kvm:
+ fprintf(stderr, "KVM exit reason: %" PRIu32 " (\"%s\")\n",
+ kvm->kvm_run->exit_reason,
+ kvm_exit_reasons[kvm->kvm_run->exit_reason]);
+ if (kvm->kvm_run->exit_reason == KVM_EXIT_UNKNOWN)
+ fprintf(stderr, "KVM exit code: 0x%" PRIu64 "\n",
+ kvm->kvm_run->hw.hardware_exit_reason);
+ disk_image__close(kvm->disk_image);
+ kvm__show_registers(kvm);
+ kvm__show_code(kvm);
+ kvm__show_page_tables(kvm);
+ kvm__delete(kvm);
+
+ return 1;
+}
diff --git a/tools/kvm/main.c b/tools/kvm/main.c
index 5bcefde..4fbb268 100644
--- a/tools/kvm/main.c
+++ b/tools/kvm/main.c
@@ -1,221 +1,22 @@
-#include "kvm/kvm.h"
-
-#include "kvm/8250-serial.h"
-#include "kvm/blk-virtio.h"
-#include "kvm/console-virtio.h"
-#include "kvm/disk-image.h"
-#include "kvm/util.h"
-#include "kvm/pci.h"
-#include "kvm/term.h"
-
-#include <inttypes.h>
-#include <signal.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
#include <stdio.h>
-extern bool ioport_debug;
-extern int active_console;
-
-static void usage(char *argv[])
-{
- fprintf(stderr, " usage: %s "
- "[--single-step] [--ioport-debug] [--enable-virtio-console] "
- "[--kvm-dev=<device>] [--mem=<size-in-MiB>] [--params=<kernel-params>] "
- "[--initrd=<initrd>] [--kernel=]<kernel-image> [--image=]<disk-image>\n",
- argv[0]);
- exit(1);
-}
-
-static struct kvm *kvm;
+/* user defined header files */
+#include <kvm/kvm-cmd.h>
+#include <kvm/kvm-help.h>
+#include <kvm/kvm-run.h>
-static void handle_sigint(int sig)
+static int handle_kvm_command(int argc, char **argv)
{
- exit(1);
-}
-
-static void handle_sigquit(int sig)
-{
- kvm__show_registers(kvm);
- kvm__show_code(kvm);
- kvm__show_page_tables(kvm);
- kvm__delete(kvm);
-
- exit(1);
-}
-
-static char real_cmdline[2048];
+ struct cmd_struct command[] = {
+ { "help", kvm_cmd_help, 0 },
+ { "run", kvm_cmd_run, 0 },
+ { NULL, NULL, 0 },
+ };
-static bool option_matches(char *arg, const char *option)
-{
- return !strncmp(arg, option, strlen(option));
+ return handle_command(command, argc, (const char **) &argv[0]);
}
int main(int argc, char *argv[])
{
- const char *kernel_filename = NULL;
- const char *initrd_filename = NULL;
- const char *image_filename = NULL;
- const char *kernel_cmdline = NULL;
- const char *kvm_dev = "/dev/kvm";
- unsigned long ram_size = 64UL << 20;
- bool single_step = false;
- int i;
-
- signal(SIGQUIT, handle_sigquit);
- signal(SIGINT, handle_sigint);
-
- for (i = 1; i < argc; i++) {
- if (option_matches(argv[i], "--kernel=")) {
- kernel_filename = &argv[i][9];
- continue;
- } else if (option_matches(argv[i], "--image=")) {
- image_filename = &argv[i][8];
- continue;
- } else if (option_matches(argv[i], "--initrd=")) {
- initrd_filename = &argv[i][9];
- continue;
- } else if (option_matches(argv[i], "--params=")) {
- kernel_cmdline = &argv[i][9];
- continue;
- } else if (option_matches(argv[i], "--kvm-dev=")) {
- kvm_dev = &argv[i][10];
- continue;
- } else if (option_matches(argv[i], "--single-step")) {
- single_step = true;
- continue;
- } else if (option_matches(argv[i], "--enable-virtio-console")) {
- active_console = CONSOLE_VIRTIO;
- continue;
- } else if (option_matches(argv[i], "--mem=")) {
- unsigned long val = atol(&argv[i][6]) << 20;
- if (val < ram_size)
- die("Not enough memory specified: %sMB (min %luMB)",
- argv[i], ram_size >> 20);
- ram_size = val;
- continue;
- } else if (option_matches(argv[i], "--ioport-debug")) {
- ioport_debug = true;
- continue;
- } else {
- /* any unspecified arg is kernel image */
- if (argv[i][0] != '-')
- kernel_filename = argv[i];
- else
- warning("Unknown option: %s", argv[i]);
- }
- }
-
- /* at least we should have kernel image passed */
- if (!kernel_filename)
- usage(argv);
-
- term_init();
-
- kvm = kvm__init(kvm_dev, ram_size);
-
- if (image_filename) {
- kvm->disk_image = disk_image__open(image_filename);
- if (!kvm->disk_image)
- die("unable to load disk image %s", image_filename);
- }
-
- kvm__setup_cpuid(kvm);
-
- strcpy(real_cmdline, "notsc nolapic noacpi pci=conf1 console=ttyS0 ");
- if (!kernel_cmdline || !strstr(kernel_cmdline, "root="))
- strlcat(real_cmdline, "root=/dev/vda rw ", sizeof(real_cmdline));
-
- if (kernel_cmdline) {
- strlcat(real_cmdline, kernel_cmdline, sizeof(real_cmdline));
- real_cmdline[sizeof(real_cmdline)-1] = '\0';
- }
-
- if (!kvm__load_kernel(kvm, kernel_filename, initrd_filename, real_cmdline))
- die("unable to load kernel %s", kernel_filename);
-
- kvm__reset_vcpu(kvm);
-
- kvm__setup_bios(kvm);
-
- if (single_step)
- kvm__enable_singlestep(kvm);
-
- serial8250__init(kvm);
-
- pci__init();
-
- blk_virtio__init(kvm);
-
- virtio_console__init(kvm);
-
- kvm__start_timer(kvm);
-
- for (;;) {
- kvm__run(kvm);
-
- switch (kvm->kvm_run->exit_reason) {
- case KVM_EXIT_DEBUG:
- kvm__show_registers(kvm);
- kvm__show_code(kvm);
- break;
- case KVM_EXIT_IO: {
- bool ret;
-
- ret = kvm__emulate_io(kvm,
- kvm->kvm_run->io.port,
- (uint8_t *)kvm->kvm_run + kvm->kvm_run->io.data_offset,
- kvm->kvm_run->io.direction,
- kvm->kvm_run->io.size,
- kvm->kvm_run->io.count);
-
- if (!ret)
- goto panic_kvm;
- break;
- }
- case KVM_EXIT_MMIO: {
- bool ret;
-
- ret = kvm__emulate_mmio(kvm,
- kvm->kvm_run->mmio.phys_addr,
- kvm->kvm_run->mmio.data,
- kvm->kvm_run->mmio.len,
- kvm->kvm_run->mmio.is_write);
-
- if (!ret)
- goto panic_kvm;
- break;
- }
- case KVM_EXIT_INTR: {
- serial8250__inject_interrupt(kvm);
- virtio_console__inject_interrupt(kvm);
- break;
- }
- case KVM_EXIT_SHUTDOWN:
- goto exit_kvm;
- default:
- goto panic_kvm;
- }
- }
-exit_kvm:
- disk_image__close(kvm->disk_image);
- kvm__delete(kvm);
-
- return 0;
-
-panic_kvm:
- fprintf(stderr, "KVM exit reason: %" PRIu32 " (\"%s\")\n",
- kvm->kvm_run->exit_reason, kvm_exit_reasons[kvm->kvm_run->exit_reason]);
- if (kvm->kvm_run->exit_reason == KVM_EXIT_UNKNOWN)
- fprintf(stderr, "KVM exit code: 0x%" PRIu64 "\n",
- kvm->kvm_run->hw.hardware_exit_reason);
- disk_image__close(kvm->disk_image);
- kvm__show_registers(kvm);
- kvm__show_code(kvm);
- kvm__show_page_tables(kvm);
- kvm__delete(kvm);
-
- return 1;
+ return handle_kvm_command(argc - 1, &argv[1]);
}
--
1.7.1
^ permalink raw reply related [flat|nested] 4+ messages in thread