]> git.proxmox.com Git - mirror_qemu.git/commitdiff
Merge remote-tracking branch 'kwolf/for-anthony' into staging
authorAnthony Liguori <anthony@codemonkey.ws>
Tue, 3 Sep 2013 17:32:45 +0000 (12:32 -0500)
committerAnthony Liguori <anthony@codemonkey.ws>
Tue, 3 Sep 2013 17:32:46 +0000 (12:32 -0500)
# By Max Reitz (11) and others
# Via Kevin Wolf
* kwolf/for-anthony: (26 commits)
  qemu-iotests: Overlapping cluster allocations
  qcow2_check: Mark image consistent
  qcow2-refcount: Repair shared refcount blocks
  qcow2-refcount: Repair OFLAG_COPIED errors
  qcow2-refcount: Move OFLAG_COPIED checks
  qcow2: Employ metadata overlap checks
  qcow2: Metadata overlap checks
  qcow2: Add corrupt bit
  qemu-iotests: Snapshotting zero clusters
  qcow2-refcount: Snapshot update for zero clusters
  option: Add assigned flag to QEMUOptionParameter
  gluster: Abort on AIO completion failure
  block: Remove old raw driver
  switch raw block driver from "raw.o" to "raw_bsd.o"
  raw_bsd: register bdrv_raw
  raw_bsd: add raw_create_options
  raw_bsd: introduce "special members"
  raw_bsd: add raw_create()
  raw_bsd: emit debug events in bdrv_co_readv() and bdrv_co_writev()
  add skeleton for BSD licensed "raw" BlockDriver
  ...

Message-id: 1378111792-20436-1-git-send-email-kwolf@redhat.com
Signed-off-by: Anthony Liguori <anthony@codemonkey.ws>
1  2 
monitor.c

diff --combined monitor.c
index 0aeaf6c56b8a8983c787d068fa90c763fd55dda2,2c542e1bca5e58a9950ab9570411c839859d12d5..ec31b6e6a527677cd157f9476a42017679be6042
+++ b/monitor.c
@@@ -83,7 -83,6 +83,7 @@@
   * 'F'          filename
   * 'B'          block device name
   * 's'          string (accept optional quote)
 + * 'S'          it just appends the rest of the string (accept optional quote)
   * 'O'          option string of the form NAME=VALUE,...
   *              parsed according to QemuOptsList given by its name
   *              Example: 'device:O' uses qemu_device_opts.
@@@ -196,7 -195,6 +196,7 @@@ struct Monitor 
      CPUState *mon_cpu;
      BlockDriverCompletionFunc *password_completion_cb;
      void *password_opaque;
 +    mon_cmd_t *cmd_table;
      QError *error;
      QLIST_HEAD(,mon_fd_t) fds;
      QLIST_ENTRY(Monitor) entry;
@@@ -506,6 -504,7 +506,7 @@@ static const char *monitor_event_names[
      [QEVENT_BALLOON_CHANGE] = "BALLOON_CHANGE",
      [QEVENT_SPICE_MIGRATE_COMPLETED] = "SPICE_MIGRATE_COMPLETED",
      [QEVENT_GUEST_PANICKED] = "GUEST_PANICKED",
+     [QEVENT_BLOCK_IMAGE_CORRUPTED] = "BLOCK_IMAGE_CORRUPTED",
  };
  QEMU_BUILD_BUG_ON(ARRAY_SIZE(monitor_event_names) != QEVENT_MAX)
  
@@@ -685,26 -684,14 +686,26 @@@ static int do_qmp_capabilities(Monitor 
  
  static void handle_user_command(Monitor *mon, const char *cmdline);
  
 +static void monitor_data_init(Monitor *mon)
 +{
 +    memset(mon, 0, sizeof(Monitor));
 +    mon->outbuf = qstring_new();
 +    /* Use *mon_cmds by default. */
 +    mon->cmd_table = mon_cmds;
 +}
 +
 +static void monitor_data_destroy(Monitor *mon)
 +{
 +    QDECREF(mon->outbuf);
 +}
 +
  char *qmp_human_monitor_command(const char *command_line, bool has_cpu_index,
                                  int64_t cpu_index, Error **errp)
  {
      char *output = NULL;
      Monitor *old_mon, hmp;
  
 -    memset(&hmp, 0, sizeof(hmp));
 -    hmp.outbuf = qstring_new();
 +    monitor_data_init(&hmp);
      hmp.skip_flush = true;
  
      old_mon = cur_mon;
      }
  
  out:
 -    QDECREF(hmp.outbuf);
 +    monitor_data_destroy(&hmp);
      return output;
  }
  
@@@ -754,202 -741,33 +755,202 @@@ static int compare_cmd(const char *name
      return 0;
  }
  
 +static int get_str(char *buf, int buf_size, const char **pp)
 +{
 +    const char *p;
 +    char *q;
 +    int c;
 +
 +    q = buf;
 +    p = *pp;
 +    while (qemu_isspace(*p)) {
 +        p++;
 +    }
 +    if (*p == '\0') {
 +    fail:
 +        *q = '\0';
 +        *pp = p;
 +        return -1;
 +    }
 +    if (*p == '\"') {
 +        p++;
 +        while (*p != '\0' && *p != '\"') {
 +            if (*p == '\\') {
 +                p++;
 +                c = *p++;
 +                switch (c) {
 +                case 'n':
 +                    c = '\n';
 +                    break;
 +                case 'r':
 +                    c = '\r';
 +                    break;
 +                case '\\':
 +                case '\'':
 +                case '\"':
 +                    break;
 +                default:
 +                    qemu_printf("unsupported escape code: '\\%c'\n", c);
 +                    goto fail;
 +                }
 +                if ((q - buf) < buf_size - 1) {
 +                    *q++ = c;
 +                }
 +            } else {
 +                if ((q - buf) < buf_size - 1) {
 +                    *q++ = *p;
 +                }
 +                p++;
 +            }
 +        }
 +        if (*p != '\"') {
 +            qemu_printf("unterminated string\n");
 +            goto fail;
 +        }
 +        p++;
 +    } else {
 +        while (*p != '\0' && !qemu_isspace(*p)) {
 +            if ((q - buf) < buf_size - 1) {
 +                *q++ = *p;
 +            }
 +            p++;
 +        }
 +    }
 +    *q = '\0';
 +    *pp = p;
 +    return 0;
 +}
 +
 +#define MAX_ARGS 16
 +
 +static void free_cmdline_args(char **args, int nb_args)
 +{
 +    int i;
 +
 +    assert(nb_args <= MAX_ARGS);
 +
 +    for (i = 0; i < nb_args; i++) {
 +        g_free(args[i]);
 +    }
 +
 +}
 +
 +/*
 + * Parse the command line to get valid args.
 + * @cmdline: command line to be parsed.
 + * @pnb_args: location to store the number of args, must NOT be NULL.
 + * @args: location to store the args, which should be freed by caller, must
 + *        NOT be NULL.
 + *
 + * Returns 0 on success, negative on failure.
 + *
 + * NOTE: this parser is an approximate form of the real command parser. Number
 + *       of args have a limit of MAX_ARGS. If cmdline contains more, it will
 + *       return with failure.
 + */
 +static int parse_cmdline(const char *cmdline,
 +                         int *pnb_args, char **args)
 +{
 +    const char *p;
 +    int nb_args, ret;
 +    char buf[1024];
 +
 +    p = cmdline;
 +    nb_args = 0;
 +    for (;;) {
 +        while (qemu_isspace(*p)) {
 +            p++;
 +        }
 +        if (*p == '\0') {
 +            break;
 +        }
 +        if (nb_args >= MAX_ARGS) {
 +            goto fail;
 +        }
 +        ret = get_str(buf, sizeof(buf), &p);
 +        if (ret < 0) {
 +            goto fail;
 +        }
 +        args[nb_args] = g_strdup(buf);
 +        nb_args++;
 +    }
 +    *pnb_args = nb_args;
 +    return 0;
 +
 + fail:
 +    free_cmdline_args(args, nb_args);
 +    return -1;
 +}
 +
 +static void help_cmd_dump_one(Monitor *mon,
 +                              const mon_cmd_t *cmd,
 +                              char **prefix_args,
 +                              int prefix_args_nb)
 +{
 +    int i;
 +
 +    for (i = 0; i < prefix_args_nb; i++) {
 +        monitor_printf(mon, "%s ", prefix_args[i]);
 +    }
 +    monitor_printf(mon, "%s %s -- %s\n", cmd->name, cmd->params, cmd->help);
 +}
 +
 +/* @args[@arg_index] is the valid command need to find in @cmds */
  static void help_cmd_dump(Monitor *mon, const mon_cmd_t *cmds,
 -                          const char *prefix, const char *name)
 +                          char **args, int nb_args, int arg_index)
  {
      const mon_cmd_t *cmd;
  
 -    for(cmd = cmds; cmd->name != NULL; cmd++) {
 -        if (!name || !strcmp(name, cmd->name))
 -            monitor_printf(mon, "%s%s %s -- %s\n", prefix, cmd->name,
 -                           cmd->params, cmd->help);
 +    /* No valid arg need to compare with, dump all in *cmds */
 +    if (arg_index >= nb_args) {
 +        for (cmd = cmds; cmd->name != NULL; cmd++) {
 +            help_cmd_dump_one(mon, cmd, args, arg_index);
 +        }
 +        return;
 +    }
 +
 +    /* Find one entry to dump */
 +    for (cmd = cmds; cmd->name != NULL; cmd++) {
 +        if (compare_cmd(args[arg_index], cmd->name)) {
 +            if (cmd->sub_table) {
 +                /* continue with next arg */
 +                help_cmd_dump(mon, cmd->sub_table,
 +                              args, nb_args, arg_index + 1);
 +            } else {
 +                help_cmd_dump_one(mon, cmd, args, arg_index);
 +            }
 +            break;
 +        }
      }
  }
  
  static void help_cmd(Monitor *mon, const char *name)
  {
 -    if (name && !strcmp(name, "info")) {
 -        help_cmd_dump(mon, info_cmds, "info ", NULL);
 -    } else {
 -        help_cmd_dump(mon, mon_cmds, "", name);
 -        if (name && !strcmp(name, "log")) {
 +    char *args[MAX_ARGS];
 +    int nb_args = 0;
 +
 +    /* 1. parse user input */
 +    if (name) {
 +        /* special case for log, directly dump and return */
 +        if (!strcmp(name, "log")) {
              const QEMULogItem *item;
              monitor_printf(mon, "Log items (comma separated):\n");
              monitor_printf(mon, "%-10s %s\n", "none", "remove all logs");
              for (item = qemu_log_items; item->mask != 0; item++) {
                  monitor_printf(mon, "%-10s %s\n", item->name, item->help);
              }
 +            return;
 +        }
 +
 +        if (parse_cmdline(name, &nb_args, args) < 0) {
 +            return;
          }
      }
 +
 +    /* 2. dump the contents according to parsed args */
 +    help_cmd_dump(mon, mon->cmd_table, args, nb_args, 0);
 +
 +    free_cmdline_args(args, nb_args);
  }
  
  static void do_help_cmd(Monitor *mon, const QDict *qdict)
@@@ -3354,8 -3172,7 +3355,8 @@@ static const MonitorDef monitor_defs[] 
      { NULL },
  };
  
 -static void expr_error(Monitor *mon, const char *fmt, ...)
 +static void GCC_FMT_ATTR(2, 3) QEMU_NORETURN
 +expr_error(Monitor *mon, const char *fmt, ...)
  {
      va_list ap;
      va_start(ap, fmt);
@@@ -3604,6 -3421,71 +3605,6 @@@ static int get_double(Monitor *mon, dou
      return 0;
  }
  
 -static int get_str(char *buf, int buf_size, const char **pp)
 -{
 -    const char *p;
 -    char *q;
 -    int c;
 -
 -    q = buf;
 -    p = *pp;
 -    while (qemu_isspace(*p))
 -        p++;
 -    if (*p == '\0') {
 -    fail:
 -        *q = '\0';
 -        *pp = p;
 -        return -1;
 -    }
 -    if (*p == '\"') {
 -        p++;
 -        while (*p != '\0' && *p != '\"') {
 -            if (*p == '\\') {
 -                p++;
 -                c = *p++;
 -                switch(c) {
 -                case 'n':
 -                    c = '\n';
 -                    break;
 -                case 'r':
 -                    c = '\r';
 -                    break;
 -                case '\\':
 -                case '\'':
 -                case '\"':
 -                    break;
 -                default:
 -                    qemu_printf("unsupported escape code: '\\%c'\n", c);
 -                    goto fail;
 -                }
 -                if ((q - buf) < buf_size - 1) {
 -                    *q++ = c;
 -                }
 -            } else {
 -                if ((q - buf) < buf_size - 1) {
 -                    *q++ = *p;
 -                }
 -                p++;
 -            }
 -        }
 -        if (*p != '\"') {
 -            qemu_printf("unterminated string\n");
 -            goto fail;
 -        }
 -        p++;
 -    } else {
 -        while (*p != '\0' && !qemu_isspace(*p)) {
 -            if ((q - buf) < buf_size - 1) {
 -                *q++ = *p;
 -            }
 -            p++;
 -        }
 -    }
 -    *q = '\0';
 -    *pp = p;
 -    return 0;
 -}
 -
  /*
   * Store the command-name in cmdname, and return a pointer to
   * the remaining of the command string.
@@@ -3660,6 -3542,8 +3661,6 @@@ static char *key_get_info(const char *t
  static int default_fmt_format = 'x';
  static int default_fmt_size = 4;
  
 -#define MAX_ARGS 16
 -
  static int is_valid_option(const char *c, const char *typestr)
  {
      char option[3];
@@@ -4048,31 -3932,6 +4049,31 @@@ static const mon_cmd_t *monitor_parse_c
                  }
              }
              break;
 +        case 'S':
 +            {
 +                /* package all remaining string */
 +                int len;
 +
 +                while (qemu_isspace(*p)) {
 +                    p++;
 +                }
 +                if (*typestr == '?') {
 +                    typestr++;
 +                    if (*p == '\0') {
 +                        /* no remaining string: NULL argument */
 +                        break;
 +                    }
 +                }
 +                len = strlen(p);
 +                if (len <= 0) {
 +                    monitor_printf(mon, "%s: string expected\n",
 +                                   cmdname);
 +                    break;
 +                }
 +                qdict_put(qdict, key, qstring_from_str(p));
 +                p += len;
 +            }
 +            break;
          default:
          bad_type:
              monitor_printf(mon, "%s: unknown type '%c'\n", cmdname, c);
@@@ -4126,7 -3985,7 +4127,7 @@@ static void handle_user_command(Monito
  
      qdict = qdict_new();
  
 -    cmd = monitor_parse_command(mon, cmdline, 0, mon_cmds, qdict);
 +    cmd = monitor_parse_command(mon, cmdline, 0, mon->cmd_table, qdict);
      if (!cmd)
          goto out;
  
@@@ -4150,7 -4009,7 +4151,7 @@@ out
      QDECREF(qdict);
  }
  
 -static void cmd_completion(const char *name, const char *list)
 +static void cmd_completion(Monitor *mon, const char *name, const char *list)
  {
      const char *p, *pstart;
      char cmd[128];
          memcpy(cmd, pstart, len);
          cmd[len] = '\0';
          if (name[0] == '\0' || !strncmp(name, cmd, strlen(name))) {
 -            readline_add_completion(cur_mon->rs, cmd);
 +            readline_add_completion(mon->rs, cmd);
          }
          if (*p == '\0')
              break;
      }
  }
  
 -static void file_completion(const char *input)
 +static void file_completion(Monitor *mon, const char *input)
  {
      DIR *ffs;
      struct dirent *d;
          pstrcpy(file_prefix, sizeof(file_prefix), p + 1);
      }
  #ifdef DEBUG_COMPLETION
 -    monitor_printf(cur_mon, "input='%s' path='%s' prefix='%s'\n",
 +    monitor_printf(mon, "input='%s' path='%s' prefix='%s'\n",
                     input, path, file_prefix);
  #endif
      ffs = opendir(path);
              if (stat(file, &sb) == 0 && S_ISDIR(sb.st_mode)) {
                  pstrcat(file, sizeof(file), "/");
              }
 -            readline_add_completion(cur_mon->rs, file);
 +            readline_add_completion(mon->rs, file);
          }
      }
      closedir(ffs);
  }
  
 +typedef struct MonitorBlockComplete {
 +    Monitor *mon;
 +    const char *input;
 +} MonitorBlockComplete;
 +
  static void block_completion_it(void *opaque, BlockDriverState *bs)
  {
      const char *name = bdrv_get_device_name(bs);
 -    const char *input = opaque;
 +    MonitorBlockComplete *mbc = opaque;
 +    Monitor *mon = mbc->mon;
 +    const char *input = mbc->input;
  
      if (input[0] == '\0' ||
          !strncmp(name, (char *)input, strlen(input))) {
 -        readline_add_completion(cur_mon->rs, name);
 -    }
 -}
 -
 -/* NOTE: this parser is an approximate form of the real command parser */
 -static void parse_cmdline(const char *cmdline,
 -                         int *pnb_args, char **args)
 -{
 -    const char *p;
 -    int nb_args, ret;
 -    char buf[1024];
 -
 -    p = cmdline;
 -    nb_args = 0;
 -    for(;;) {
 -        while (qemu_isspace(*p))
 -            p++;
 -        if (*p == '\0')
 -            break;
 -        if (nb_args >= MAX_ARGS)
 -            break;
 -        ret = get_str(buf, sizeof(buf), &p);
 -        args[nb_args] = g_strdup(buf);
 -        nb_args++;
 -        if (ret < 0)
 -            break;
 +        readline_add_completion(mon->rs, name);
      }
 -    *pnb_args = nb_args;
  }
  
  static const char *next_arg_type(const char *typestr)
      return (p != NULL ? ++p : typestr);
  }
  
 -static void monitor_find_completion(const char *cmdline)
 +static void monitor_find_completion_by_table(Monitor *mon,
 +                                             const mon_cmd_t *cmd_table,
 +                                             char **args,
 +                                             int nb_args)
  {
      const char *cmdname;
 -    char *args[MAX_ARGS];
 -    int nb_args, i, len;
 +    int i;
      const char *ptype, *str;
      const mon_cmd_t *cmd;
 +    MonitorBlockComplete mbs;
  
 -    parse_cmdline(cmdline, &nb_args, args);
 -#ifdef DEBUG_COMPLETION
 -    for(i = 0; i < nb_args; i++) {
 -        monitor_printf(cur_mon, "arg%d = '%s'\n", i, (char *)args[i]);
 -    }
 -#endif
 -
 -    /* if the line ends with a space, it means we want to complete the
 -       next arg */
 -    len = strlen(cmdline);
 -    if (len > 0 && qemu_isspace(cmdline[len - 1])) {
 -        if (nb_args >= MAX_ARGS) {
 -            goto cleanup;
 -        }
 -        args[nb_args++] = g_strdup("");
 -    }
      if (nb_args <= 1) {
          /* command completion */
          if (nb_args == 0)
              cmdname = "";
          else
              cmdname = args[0];
 -        readline_set_completion_index(cur_mon->rs, strlen(cmdname));
 -        for(cmd = mon_cmds; cmd->name != NULL; cmd++) {
 -            cmd_completion(cmdname, cmd->name);
 +        readline_set_completion_index(mon->rs, strlen(cmdname));
 +        for (cmd = cmd_table; cmd->name != NULL; cmd++) {
 +            cmd_completion(mon, cmdname, cmd->name);
          }
      } else {
          /* find the command */
 -        for (cmd = mon_cmds; cmd->name != NULL; cmd++) {
 +        for (cmd = cmd_table; cmd->name != NULL; cmd++) {
              if (compare_cmd(args[0], cmd->name)) {
                  break;
              }
          }
          if (!cmd->name) {
 -            goto cleanup;
 +            return;
 +        }
 +
 +        if (cmd->sub_table) {
 +            /* do the job again */
 +            return monitor_find_completion_by_table(mon, cmd->sub_table,
 +                                                    &args[1], nb_args - 1);
          }
  
          ptype = next_arg_type(cmd->args_type);
          switch(*ptype) {
          case 'F':
              /* file completion */
 -            readline_set_completion_index(cur_mon->rs, strlen(str));
 -            file_completion(str);
 +            readline_set_completion_index(mon->rs, strlen(str));
 +            file_completion(mon, str);
              break;
          case 'B':
              /* block device name completion */
 -            readline_set_completion_index(cur_mon->rs, strlen(str));
 -            bdrv_iterate(block_completion_it, (void *)str);
 +            mbs.mon = mon;
 +            mbs.input = str;
 +            readline_set_completion_index(mon->rs, strlen(str));
 +            bdrv_iterate(block_completion_it, &mbs);
              break;
          case 's':
 -            /* XXX: more generic ? */
 -            if (!strcmp(cmd->name, "info")) {
 -                readline_set_completion_index(cur_mon->rs, strlen(str));
 -                for(cmd = info_cmds; cmd->name != NULL; cmd++) {
 -                    cmd_completion(str, cmd->name);
 -                }
 -            } else if (!strcmp(cmd->name, "sendkey")) {
 +        case 'S':
 +            if (!strcmp(cmd->name, "sendkey")) {
                  char *sep = strrchr(str, '-');
                  if (sep)
                      str = sep + 1;
 -                readline_set_completion_index(cur_mon->rs, strlen(str));
 +                readline_set_completion_index(mon->rs, strlen(str));
                  for (i = 0; i < Q_KEY_CODE_MAX; i++) {
 -                    cmd_completion(str, QKeyCode_lookup[i]);
 +                    cmd_completion(mon, str, QKeyCode_lookup[i]);
                  }
              } else if (!strcmp(cmd->name, "help|?")) {
 -                readline_set_completion_index(cur_mon->rs, strlen(str));
 -                for (cmd = mon_cmds; cmd->name != NULL; cmd++) {
 -                    cmd_completion(str, cmd->name);
 -                }
 +                monitor_find_completion_by_table(mon, cmd_table,
 +                                                 &args[1], nb_args - 1);
              }
              break;
          default:
              break;
          }
      }
 +}
  
 -cleanup:
 +static void monitor_find_completion(Monitor *mon,
 +                                    const char *cmdline)
 +{
 +    char *args[MAX_ARGS];
 +    int nb_args, len;
 +
 +    /* 1. parse the cmdline */
 +    if (parse_cmdline(cmdline, &nb_args, args) < 0) {
 +        return;
 +    }
 +#ifdef DEBUG_COMPLETION
      for (i = 0; i < nb_args; i++) {
 -        g_free(args[i]);
 +        monitor_printf(mon, "arg%d = '%s'\n", i, args[i]);
 +    }
 +#endif
 +
 +    /* if the line ends with a space, it means we want to complete the
 +       next arg */
 +    len = strlen(cmdline);
 +    if (len > 0 && qemu_isspace(cmdline[len - 1])) {
 +        if (nb_args >= MAX_ARGS) {
 +            goto cleanup;
 +        }
 +        args[nb_args++] = g_strdup("");
      }
 +
 +    /* 2. auto complete according to args */
 +    monitor_find_completion_by_table(mon, mon->cmd_table, args, nb_args);
 +
 +cleanup:
 +    free_cmdline_args(args, nb_args);
  }
  
  static int monitor_can_read(void *opaque)
@@@ -4890,12 -4752,11 +4891,12 @@@ void monitor_init(CharDriverState *chr
  
      if (is_first_init) {
          monitor_protocol_event_init();
 +        sortcmdlist();
          is_first_init = 0;
      }
  
 -    mon = g_malloc0(sizeof(*mon));
 -    mon->outbuf = qstring_new();
 +    mon = g_malloc(sizeof(*mon));
 +    monitor_data_init(mon);
  
      mon->chr = chr;
      mon->flags = flags;
      QLIST_INSERT_HEAD(&mon_list, mon, entry);
      if (!default_mon || (flags & MONITOR_IS_DEFAULT))
          default_mon = mon;
 -
 -    sortcmdlist();
  }
  
  static void bdrv_password_cb(Monitor *mon, const char *password, void *opaque)