[libvirt] [PATCH 3/3] Get QEMU pty paths from the monitor

Daniel P. Berrange berrange at redhat.com
Wed Nov 25 11:31:37 UTC 2009


On Mon, Nov 23, 2009 at 12:30:29PM +0000, Matthew Booth wrote:
> This change makes the QEMU driver get pty paths from the output of the monitor
> 'info chardev' command. This output is structured, and contains both the name of
> the device and the path on the same line. This is considerably more reliable
> than parsing the startup log output, which requires the parsing code to know
> which order QEMU will print pty information in.
> 
> Note that we still need to parse the log output as the monitor itself may be on
> a pty. This should be rare, however, and the new code will replace all pty paths
> parsed by the log output method once the monitor is available.
> 
> * src/qemu/qemu_monitor.(c|h) src/qemu_monitor_text.(c|h): Implement
>   qemuMonitorGetPtyPaths().
> * src/qemu/qemu_driver.c: Get pty path information using
>   qemuMonitorGetPtyPaths().
> ---
>  src/qemu/qemu_driver.c       |   68 +++++++++++++++++++++++++++++++++++++++-
>  src/qemu/qemu_monitor.c      |    9 +++++
>  src/qemu/qemu_monitor.h      |    3 ++
>  src/qemu/qemu_monitor_text.c |   71 ++++++++++++++++++++++++++++++++++++++++++
>  src/qemu/qemu_monitor_text.h |    4 ++
>  5 files changed, 153 insertions(+), 2 deletions(-)
> 
> diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
> index ebf44b0..90dd9cd 100644
> --- a/src/qemu/qemu_driver.c
> +++ b/src/qemu/qemu_driver.c
> @@ -1239,6 +1239,40 @@ qemudExtractTTYPath(virConnectPtr conn,
>  }
>  
>  static int
> +qemudFindCharDevicePTYsMonitor(virConnectPtr conn,
> +                               virDomainObjPtr vm,
> +                               virHashTablePtr paths)
> +{
> +    int i;
> +
> +#define LOOKUP_PTYS(array, arraylen, idprefix) \
> +    for (i = 0 ; i < (arraylen) ; i++) { \
> +        virDomainChrDefPtr chr = (array)[i]; \
> +        if (chr->type == VIR_DOMAIN_CHR_TYPE_PTY) { \
> +            char id[16]; \
> +\
> +            if (snprintf(id, sizeof(id), idprefix "%i", i) >= sizeof(id)) \
> +                return -1; \
> +\
> +            const char *path = (const char *) virHashLookup(paths, id); \
> +            if (path == NULL) { \
> +                qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, \
> +                                 _("no assigned pty for device %s"), id); \
> +                return -1; \
> +            } \
> +\
> +            chr->data.file.path = strdup(path); \
> +        } \
> +    }

Can you indent the  \  to they all line up in the right hand side. 

> +
> +    LOOKUP_PTYS(vm->def->serials,   vm->def->nserials,   "serial");
> +    LOOKUP_PTYS(vm->def->parallels, vm->def->nparallels, "parallel");
> +    LOOKUP_PTYS(vm->def->channels,  vm->def->nchannels,  "channel");
> +

#undef LOOKUP_PTYS

> +    return 0;
> +}
> +
> +static int
>  qemudFindCharDevicePTYs(virConnectPtr conn,
>                          virDomainObjPtr vm,
>                          const char *output,
> @@ -1284,6 +1318,11 @@ qemudFindCharDevicePTYs(virConnectPtr conn,
>      return 0;
>  }
>  
> +static void qemudFreePtyPath(void *payload, const char *name ATTRIBUTE_UNUSED)
> +{
> +    free(payload);

VIR_FREE

> +}
> +
>  static int
>  qemudWaitForMonitor(virConnectPtr conn,
>                      struct qemud_driver* driver,
> @@ -1291,7 +1330,7 @@ qemudWaitForMonitor(virConnectPtr conn,
>  {
>      char buf[4096]; /* Plenty of space to get startup greeting */
>      int logfd;
> -    int ret;
> +    int ret = -1;
>  
>      if ((logfd = qemudLogReadFD(conn, driver->logDir, vm->def->name, pos))
>          < 0)
> @@ -1317,7 +1356,32 @@ qemudWaitForMonitor(virConnectPtr conn,
>      if (qemuConnectMonitor(vm) < 0)
>          return -1;
>  
> -    return 0;
> +    /* Try to get the pty path mappings again via the monitor. This is much more
> +     * reliable if it's available.
> +     * Note that the monitor itself can be on a pty, so we still need to try the
> +     * log output method. */
> +    virHashTablePtr paths = virHashCreate(0);
> +    if (paths == NULL) {
> +        virReportOOMError(NULL);
> +        goto cleanup;
> +    }
> +
> +    qemuDomainObjEnterMonitor(vm);

This needs to be EnterMonitorWithDriver(driver, vm), since the 'driver'
is locked in this context

> +    qemuDomainObjPrivatePtr priv = vm->privateData;
> +    ret = qemuMonitorGetPtyPaths(priv->mon, paths);
> +    qemuDomainObjExitMonitor(vm);

And ExitMonitorWithDriver

> +
> +    VIR_DEBUG("qemuMonitorGetPtyPaths returned %i", ret);
> +    if (ret == 0) {
> +        ret = qemudFindCharDevicePTYsMonitor(conn, vm, paths);
> +    }
> +
> +cleanup:
> +    if (paths) {
> +        virHashFree(paths, qemudFreePtyPath);
> +    }
> +
> +    return ret;
>  }


> +
> +
> +/* Parse the output of "info chardev" and return a hash of pty paths.
> + *
> + * Output is:
> + * foo: filename=pty:/dev/pts/7
> + * monitor: filename=stdio
> + * serial0: filename=vc
> + * parallel0: filename=vc
> + *
> + * Non-pty lines are ignored. In the above example, key is 'foo', value is
> + * '/dev/pty/7'. The hash will contain only a single value.
> + */
> +
> +int qemuMonitorTextGetPtyPaths(qemuMonitorPtr mon,
> +                               virHashTablePtr paths)
> +{
> +    const char *cmd = "info chardev";
> +    char *reply = NULL;
> +    int ret = -1;
> +
> +    if (qemuMonitorCommand(mon, cmd, &reply) < 0) {
> +        qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED,
> +                         _("failed to retrieve chardev info in qemu with '%s'"),
> +                         cmd);
> +        goto cleanup;
> +    }
> +
> +    char *pos = reply;                  /* The current start of searching */
> +    char *end = pos + strlen(reply);    /* The end of the reply string */
> +    char *eol;                   /* The character which ends the current line */
> +
> +    while (pos < end) {
> +        /* Split the output into lines */
> +        eol = memchr(pos, '\n', end - pos);
> +        if (eol == NULL)
> +            eol = end;
> +
> +        /* Look for 'filename=pty:' */
> +#define NEEDLE "filename=pty:"
> +        char *needle = memmem(pos, eol - pos, NEEDLE, strlen(NEEDLE));
> +
> +        /* If it's not there we can ignore this line */
> +        if (!needle)
> +            goto next;
> +
> +        /* id is everthing from the beginning of the line to the ':'
> +         * find ':' and turn it into a terminator */
> +        char *colon = memchr(pos, ':', needle - pos);
> +        if (colon == NULL)
> +            goto next;
> +        *colon = '\0';
> +        char *id = pos;
> +
> +        /* Path is everything after needle to the end of the line */
> +        *eol = '\0';
> +        char *path = needle + strlen(NEEDLE);
> +
> +        virHashAddEntry(paths, id, strdup(path));

Not checking OOM on strdup() here, or for failure of virHashAddEntry()

> +#undef NEEDLE
> +
> +    next:
> +        pos = eol + 1;
> +    }
> +
> +    ret = 0;
> +
> +cleanup:
> +    VIR_FREE(reply);
> +    return ret;
> +}

Regards,
Daniel
-- 
|: Red Hat, Engineering, London   -o-   http://people.redhat.com/berrange/ :|
|: http://libvirt.org  -o-  http://virt-manager.org  -o-  http://ovirt.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505  -o-  F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|




More information about the libvir-list mailing list