qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Don Slutz <don.slutz@gmail.com>
To: Markus Armbruster <armbru@redhat.com>
Cc: "Michael S. Tsirkin" <mst@redhat.com>,
	qemu-devel@nongnu.org, "Don Slutz" <dslutz@verizon.com>,
	"Luiz Capitulino" <lcapitulino@redhat.com>,
	"Anthony Liguori" <aliguori@amazon.com>,
	"Paolo Bonzini" <pbonzini@redhat.com>,
	"Andreas Färber" <afaerber@suse.de>,
	"Richard Henderson" <rth@twiddle.net>
Subject: Re: [Qemu-devel] [PATCH v8 6/8] vmport_rpc: Add QMP access to vmport_rpc object.
Date: Fri, 03 Jul 2015 17:26:10 -0400	[thread overview]
Message-ID: <5596FDF2.1060702@Gmail.com> (raw)
In-Reply-To: <87k2uhyvkb.fsf@blackfin.pond.sub.org>

On 07/03/15 13:56, Markus Armbruster wrote:
> Don Slutz <don.slutz@gmail.com> writes:
>
>> On 07/02/15 10:11, Markus Armbruster wrote:
>>> Don Slutz <don.slutz@gmail.com> writes:
>>>
>>>> From: Don Slutz <dslutz@verizon.com>
>>>>
>>>> This adds one new inject command:
>>>>
>>>> inject-vmport-action
>>>>
>>>> And three guest info commands:
>>>>
>>>> vmport-guestinfo-set
>>>> vmport-guestinfo-get
>>>> query-vmport-guestinfo
>>>>
>>>> More details in qmp-commands.hx
>>>>
>>>> Signed-off-by: Don Slutz <dslutz@verizon.com>
>>>> CC: Don Slutz <don.slutz@gmail.com>
>>> Reviewing only the QAPI/QMP interface, plus a bit of drive-by shooting.
>>>
>>>> diff --git a/hw/misc/vmport_rpc.c b/hw/misc/vmport_rpc.c
>>>> index f157425..917898b 100644
>>>> --- a/hw/misc/vmport_rpc.c
>>>> +++ b/hw/misc/vmport_rpc.c
>>>> @@ -178,6 +178,19 @@ typedef struct VMPortRpcState {
>>>>    #endif
>>>>    } VMPortRpcState;
>>>>    +typedef int FindVMPortRpcDeviceFunc(VMPortRpcState *s, const
>>>> void *arg);
>>>> +
>>>> +/*
>>>> + * The input and output argument that find_VMPortRpc_device() uses
>>>> + * to do its work.
>>>> + */
>>>> +typedef struct VMPortRpcFind {
>>>> +    const void *arg;
>>>> +    FindVMPortRpcDeviceFunc *func;
>>>> +    int found;
>>>> +    int rc;
>>>> +} VMPortRpcFind;
>>>> +
>>>>    /* Basic request types */
>>>>    typedef enum {
>>>>        MESSAGE_TYPE_OPEN,
>>>> @@ -202,6 +215,56 @@ typedef struct {
>>>>        uint32_t edi;
>>>>    } vregs;
>>>>    +/*
>>>> + * Run func() for every VMPortRpc device, traverse the tree for
>>>> + * everything else.
>>>> + */
>>>> +static int find_VMPortRpc_device(Object *obj, void *opaque)
>>>> +{
>>>> +    VMPortRpcFind *find = opaque;
>>>> +    Object *dev;
>>>> +    VMPortRpcState *s;
>>>> +
>>>> +    assert(find);
>>>> +    if (find->found) {
>>>> +        return 0;
>>>> +    }
>>>> +    dev = object_dynamic_cast(obj, TYPE_VMPORT_RPC);
>>>> +    s = (VMPortRpcState *)dev;
>>>> +
>>>> +    if (!s) {
>>>> +        /* Container, traverse it for children */
>>>> +        return object_child_foreach(obj, find_VMPortRpc_device, opaque);
>>>> +    }
>>>> +
>>>> +    find->found++;
>>>> +    find->rc = find->func(s, find->arg);
>>>> +
>>>> +    return 0;
>>>> +}
>>>> +
>>>> +/*
>>>> + * Loop through all dynamically created VMPortRpc devices and call
>>>> + * func() for each instance.
>>>> + */
>>>> +static int foreach_dynamic_vmport_rpc_device(FindVMPortRpcDeviceFunc *func,
>>>> +                                             const void *arg)
>>>> +{
>>>> +    VMPortRpcFind find = {
>>>> +        .func = func,
>>>> +        .arg = arg,
>>>> +    };
>>>> +
>>>> +    /* Loop through all VMPortRpc devices that were spawned outside
>>>> +     * the machine */
>>>> +    find_VMPortRpc_device(qdev_get_machine(), &find);
>>>> +    if (find.found) {
>>>> +        return find.rc;
>>>> +    } else {
>>>> +        return VMPORT_DEVICE_NOT_FOUND;
>>>> +    }
>>>> +}
>>>> +
>>>>    #ifdef VMPORT_RPC_DEBUG
>>>>    /*
>>>>     * Add helper function for tracing.  This routine will convert
>>>> @@ -329,7 +392,7 @@ static int vmport_rpc_send(VMPortRpcState *s, channel_t *c,
>>>>        return rc;
>>>>    }
>>>>    -static int vmport_rpc_ctrl_send(VMPortRpcState *s, char *msg)
>>>> +static int vmport_rpc_ctrl_send(VMPortRpcState *s, const char *msg)
>>>>    {
>>>>        int rc = SEND_NOT_OPEN;
>>>>        unsigned int i;
>>>> @@ -457,6 +520,29 @@ static int get_guestinfo(VMPortRpcState *s,
>>>>        return GUESTINFO_NOTFOUND;
>>>>    }
>>>>    +static int get_qmp_guestinfo(VMPortRpcState *s,
>>>> +                             unsigned int a_key_len, const char *a_info_key,
>>>> +                             unsigned int *a_value_len, void **a_value_data)
>>>> +{
>>>> +    guestinfo_t *gi = NULL;
>>>> +
>>>> +    if (a_key_len <= MAX_KEY_LEN) {
>>>> +        gpointer key = g_strndup(a_info_key, a_key_len);
>>>> +
>>>> +        gi = (guestinfo_t *)g_hash_table_lookup(s->guestinfo, key);
>>>> +        g_free(key);
>>>> +    } else {
>>>> +        return GUESTINFO_KEYTOOLONG;
>>>> +    }
>>>> +    if (gi) {
>>>> +        *a_value_len = gi->val_len;
>>>> +        *a_value_data = gi->val_data;
>>>> +        return 0;
>>>> +    }
>>>> +
>>>> +    return GUESTINFO_NOTFOUND;
>>>> +}
>>>> +
>>>>    static int set_guestinfo(VMPortRpcState *s, int a_key_len,
>>>>                             unsigned int a_val_len, const char *a_info_key,
>>>>                             char *val)
>>>> @@ -775,7 +861,7 @@ static void vmport_rpc(VMPortRpcState *s , vregs *ur)
>>>>        }
>>>>        if (delta > s->reset_time) {
>>>>            trace_vmport_rpc_ping(delta);
>>>> -        vmport_rpc_ctrl_send(s, (char *)"reset");
>>>> +        vmport_rpc_ctrl_send(s, "reset");
>>>>        }
>>>>        vmport_rpc_sweep(s, now_time);
>>>>        do {
>>>> @@ -848,6 +934,206 @@ static uint32_t vmport_rpc_ioport_read(void *opaque, uint32_t addr)
>>>>        return ur.data[0];
>>>>    }
>>>>    +static int vmport_rpc_find_send(VMPortRpcState *s, const void
>>>> *arg)
>>>> +{
>>>> +    return vmport_rpc_ctrl_send(s, arg);
>>>> +}
>>>> +
>>>> +static void convert_local_rc(Error **errp, int rc)
>>>> +{
>>>> +    switch (rc) {
>>>> +    case 0:
>>>> +        break;
>>>> +    case VMPORT_DEVICE_NOT_FOUND:
>>>> +        error_set(errp, QERR_DEVICE_NOT_FOUND, TYPE_VMPORT_RPC);
>>>> +        break;
>>> Conflicts with
>>>
>>> commit 75158ebbe259f0bd8bf435e8f4827a43ec89c877
>>> Author: Markus Armbruster <armbru@redhat.com>
>>> Date:   Mon Mar 16 08:57:47 2015 +0100
>>>
>>>       qerror: Eliminate QERR_DEVICE_NOT_FOUND
>>>            Error classes other than ERROR_CLASS_GENERIC_ERROR should
>>> not be used
>>>       in new code.  Hiding them in QERR_ macros makes new uses hard to spot.
>>>       Fortunately, there's just one such macro left.  Eliminate it with this
>>>       coccinelle semantic patch:
>>>                @@
>>>           expression EP, E;
>>>           @@
>>>           -error_set(EP, QERR_DEVICE_NOT_FOUND, E)
>>>           +error_set(EP, ERROR_CLASS_DEVICE_NOT_FOUND, "Device '%s' not found", E)
>>>            Signed-off-by: Markus Armbruster <armbru@redhat.com>
>>>       Reviewed-by: Eric Blake <eblake@redhat.com>
>>>       Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
>>>       Reviewed-by: Luiz Capitulino <lcapitulino@redhat.com>
>>>
>>> Sorry if you explained this already for previous revisions: what's the
>>> justification for ERROR_CLASS_DEVICE_NOT_FOUND?  Can you stick to
>>> ERROR_CLASS_GENERIC_ERROR?
>> I was only coping code from other places.  Happy to convert to error_setg().
> Please do.

Ok, will do.

>
>>>> +    case SEND_NOT_OPEN:
>>>> +        error_setg(errp, "VMWare rpc not open");
>>>> +        break;
>>>> +    case SEND_SKIPPED:
>>>> +        error_setg(errp, "VMWare rpc send skipped");
>>>> +        break;
>>>> +    case SEND_TRUCATED:
>>>> +        error_setg(errp, "VMWare rpc send trucated");
>>>> +        break;
>>>> +    case SEND_NO_MEMORY:
>>>> +        error_setg(errp, "VMWare rpc send out of memory");
>>>> +        break;
>>>> +    case GUESTINFO_NOTFOUND:
>>>> +        error_setg(errp, "VMWare guestinfo not found");
>>>> +        break;
>>>> +    case GUESTINFO_VALTOOLONG:
>>>> +        error_setg(errp, "VMWare guestinfo value too long");
>>>> +        break;
>>>> +    case GUESTINFO_KEYTOOLONG:
>>>> +        error_setg(errp, "VMWare guestinfo key too long");
>>>> +        break;
>>>> +    case GUESTINFO_TOOMANYKEYS:
>>>> +        error_setg(errp, "VMWare guestinfo too many keys");
>>>> +        break;
>>>> +    case GUESTINFO_NO_MEMORY:
>>>> +        error_setg(errp, "VMWare guestinfo out of memory");
>>>> +        break;
>>>> +    default:
>>>> +        error_setg(errp, "VMWare rpc send rc=%d unknown", rc);
>>>> +        break;
>>>> +    }
>>>> +}
>>>> +
>>>> +void qmp_inject_vmport_action(enum VmportAction action, Error **errp)
>>>> +{
>>>> +    int rc;
>>>> +
>>>> +    switch (action) {
>>>> +    case VMPORT_ACTION_REBOOT:
>>>> +        rc = foreach_dynamic_vmport_rpc_device(vmport_rpc_find_send,
>>>> +                                               "OS_Reboot");
>>>> +        break;
>>>> +    case VMPORT_ACTION_HALT:
>>>> +        rc = foreach_dynamic_vmport_rpc_device(vmport_rpc_find_send,
>>>> +                                               "OS_Halt");
>>>> +        break;
>>>> +    case VMPORT_ACTION_MAX:
>>>> +        assert(action != VMPORT_ACTION_MAX);
>>> If this fails, you likely found a major compiler bug.
>> Nope.  That assert() does happen:
> Uh, I misread != for ==.  The assert *always* fails.  Sorry!
>
>>>> +        abort(); /* Should be impossible to get here. */
>>> Why not simply
>>>
>>>          default:
>>>              abort();
>> Will change to this.  abort() was added in v7.
> Thanks!
>
>>>> +    }
>>>> +    convert_local_rc(errp, rc);
>>>> +}
>>>> +
>>>> +typedef struct keyValue {
>>>> +    const char *key_data;
>>>> +    void *value_data;
>>>> +    unsigned int key_len;
>>>> +    unsigned int value_len;
>>>> +} keyValue;
>>>> +
>>>> +static int find_set(VMPortRpcState *s, const void *arg)
>>>> +{
>>>> +    const keyValue *key_value = arg;
>>>> +
>>>> +    return set_guestinfo(s, key_value->key_len, key_value->value_len,
>>>> +                         key_value->key_data, key_value->value_data);
>>>> +}
>>>> +
>>>> +static int find_get(VMPortRpcState *s, const void *arg)
>>>> +{
>>>> +    keyValue *key_value = (void *)arg;
>>>> +
>>>> +    return get_qmp_guestinfo(s, key_value->key_len, key_value->key_data,
>>>> +                             &key_value->value_len, &key_value->value_data);
>>>> +}
>>>> +
>>>> +void qmp_vmport_guestinfo_set(const char *key, const char *value,
>>>> +                              bool has_format, enum DataFormat format,
>>>> +                              Error **errp)
>>>> +{
>>>> +    int rc;
>>>> +    keyValue key_value;
>>>> +
>>>> +    if (strncmp(key, "guestinfo.", strlen("guestinfo.")) == 0) {
>>>> +        key_value.key_data = (key + strlen("guestinfo."));
>>>> +        key_value.key_len = strlen(key) - strlen("guestinfo.");
>>>> +    } else {
>>>> +        key_value.key_data = key;
>>>> +        key_value.key_len = strlen(key);
>>>> +    }
>>>> +    if (has_format && (format == DATA_FORMAT_BASE64)) {
>>>> +        gsize write_count;
>>>> +
>>>> +        key_value.value_data = g_base64_decode(value, &write_count);
>>>> +        key_value.value_len = write_count;
>>>> +    } else {
>>>> +        key_value.value_data = (void *)value;
>>>> +        key_value.value_len = strlen(value);
>>>> +    }
>>>> +
>>>> +    rc = foreach_dynamic_vmport_rpc_device(find_set, &key_value);
>>>> +
>>>> +    if (key_value.value_data != value) {
>>>> +        g_free(key_value.value_data);
>>>> +    }
>>>> +
>>>> +    if (rc) {
>>>> +        convert_local_rc(errp, rc);
>>>> +        return;
>>>> +    }
>>>> +}
>>>> +
>>>> +VmportGuestInfoValue *qmp_vmport_guestinfo_get(const char *key,
>>>> +                                               bool has_format,
>>>> +                                               enum DataFormat format,
>>>> +                                               Error **errp)
>>>> +{
>>>> +    int rc;
>>>> +    keyValue key_value;
>>>> +    VmportGuestInfoValue *ret_value;
>>>> +
>>>> +    if (strncmp(key, "guestinfo.", strlen("guestinfo.")) == 0) {
>>>> +        key_value.key_data = (key + strlen("guestinfo."));
>>>> +        key_value.key_len = strlen(key) - strlen("guestinfo.");
>>>> +    } else {
>>>> +        key_value.key_data = key;
>>>> +        key_value.key_len = strlen(key);
>>>> +    }
>>>> +
>>>> +    rc = foreach_dynamic_vmport_rpc_device(find_get, &key_value);
>>>> +    if (rc) {
>>>> +        convert_local_rc(errp, rc);
>>>> +        return NULL;
>>>> +    }
>>>> +
>>>> +    ret_value = g_new0(VmportGuestInfoValue, 1);
>>>> +    if (has_format && (format == DATA_FORMAT_BASE64)) {
>>>> +        ret_value->value = g_base64_encode(key_value.value_data,
>>>> +                                           key_value.value_len);
>>>> +    } else {
>>>> +        /*
>>>> +         * FIXME should check for complete, valid UTF-8 characters.
>>>> +         * Invalid sequences should be replaced by a suitable
>>>> +         * replacement character. Or cause an error to be raised.
>>>> +         */
>>> Thanks for copying the FIXME from qmp_ringbuf_read(), I appreciate it.
>>>
>>>> +        ret_value->value = g_malloc(key_value.value_len + 1);
>>>> +        memcpy(ret_value->value, key_value.value_data, key_value.value_len);
>>>> +        ret_value->value[key_value.value_len] = 0;
>>>> +    }
>>>> +
>>>> +    return ret_value;
>>>> +}
>>>> +
>>>> +
>>>> +static void vmport_rpc_find_list_one(gpointer key, gpointer value,
>>>> +                                     gpointer opaque)
>>>> +{
>>>> +    VmportGuestInfoKeyList **keys = opaque;
>>>> +    VmportGuestInfoKeyList *info = g_new0(VmportGuestInfoKeyList, 1);
>>>> +    char *ckey = key;
>>>> +
>>>> +    info->value = g_new0(VmportGuestInfoKey, 1);
>>>> +    info->value->key = g_strdup_printf("guestinfo.%s", ckey);
>>>> +    info->next = *keys;
>>>> +    *keys = info;
>>>> +}
>>>> +
>>>> +static int vmport_rpc_find_list(VMPortRpcState *s, const void *arg)
>>>> +{
>>>> +    g_hash_table_foreach(s->guestinfo, vmport_rpc_find_list_one, (gpointer)arg);
>>>> +    return 0;
>>>> +}
>>>> +
>>>> +VmportGuestInfoKeyList *qmp_query_vmport_guestinfo(Error **errp)
>>>> +{
>>>> +    VmportGuestInfoKeyList *keys = NULL;
>>>> +    int rc = foreach_dynamic_vmport_rpc_device(vmport_rpc_find_list,
>>>> +                                               (void *)&keys);
>>>> +
>>>> +    if (rc) {
>>>> +        convert_local_rc(errp, rc);
>>>> +    }
>>>> +
>>>> +    return keys;
>>>> +}
>>>> +
>>>> +
>>>>    static void vmport_rpc_reset(DeviceState *d)
>>>>    {
>>>>        unsigned int i;
>>>> diff --git a/monitor.c b/monitor.c
>>>> index aeea2b5..4224314 100644
>>>> --- a/monitor.c
>>>> +++ b/monitor.c
>>>> @@ -5360,4 +5360,28 @@ void qmp_rtc_reset_reinjection(Error **errp)
>>>>    {
>>>>        error_setg(errp, QERR_FEATURE_DISABLED, "rtc-reset-reinjection");
>>>>    }
>>>> +void qmp_inject_vmport_action(enum VmportAction action, Error **errp)
>>>> +{
>>>> +    error_set(errp, QERR_FEATURE_DISABLED, "inject-vmport-action");
>>>> +}
>>>> +void qmp_vmport_guestinfo_set(const char *key, const char *value,
>>>> +                              bool has_format, enum DataFormat format,
>>>> +                              Error **errp)
>>>> +{
>>>> +    error_set(errp, QERR_FEATURE_DISABLED, "vmport-guestinfo-set");
>>>> +}
>>>> +VmportGuestInfoValue *qmp_vmport_guestinfo_get(const char *key,
>>>> +                                               bool has_format,
>>>> +                                               enum DataFormat format,
>>>> +                                               Error **errp)
>>>> +{
>>>> +    error_set(errp, QERR_FEATURE_DISABLED, "vmport-guestinfo-get");
>>>> +    return NULL;
>>>> +}
>>>> +VmportGuestInfoKeyList *qmp_query_vmport_guestinfo(Error **errp)
>>>> +{
>>>> +    error_set(errp, QERR_FEATURE_DISABLED, "query-vmport-guestinfo");
>>>> +    return NULL;
>>>> +}
>>> I understand you're just following existing practice here, but I can
>>> help to wonder whether the practice is smart.  The command exists in all
>>> compile-time configurations, but it works in only some.  To figure out
>>> whether it works, you have to try it.
>>>
>>> If we add the command only when it actually works, you can use
>>> query-commands instead.
>>>
>>> This isn't a demand for you to change anything now.  We QMP guys need to
>>> decide how we want this done.
>>>
>>>>    #endif
>>> Since the #ifdef section is now longer than a few lines,
>>>
>>>     -#endif
>>>     +#endif  /* !TARGET_I386 */
>>>
>>> would be nice
>> Will add.
>>
>>>> +
>>> No blank line at end of file, please.
>> Will drop.
>>
>>>> diff --git a/qapi-schema.json b/qapi-schema.json
>>>> index 106008c..5d9e9e2 100644
>>>> --- a/qapi-schema.json
>>>> +++ b/qapi-schema.json
>>>> @@ -1429,6 +1429,107 @@
>>>>    { 'command': 'inject-nmi' }
>>>>      ##
>>>> +# @VmportAction:
>>>> +#
>>>> +# An enumeration of actions that can be requested via vmport RPC.
>>>> +#
>>>> +# @reboot: Ask the guest via VMware tools to reboot
>>>> +#
>>>> +# @halt: Ask the guest via VMware tools to halt
>>>> +#
>>>> +# Since: 2.4
>>>> +##
>>>> +{ 'enum': 'VmportAction',
>>>> +  'data': [ 'reboot', 'halt' ] }
>>>> +
>>>> +##
>>>> +# @inject-vmport-action:
>>>> +#
>>>> +# Injects a VMWare Tools action to the guest.
>>>> +#
>>>> +# Returns:  If successful, nothing
>>>> +#
>>>> +# Since:  2.4
>>>> +#
>>>> +##
>>>> +{ 'command': 'inject-vmport-action',
>>>> +  'data': {'action': 'VmportAction'} }
>>>> +
>>>> +##
>>>> +# @vmport-guestinfo-set:
>>>> +#
>>>> +# Set a VMWare Tools guestinfo key to a value
>>>> +#
>>>> +# @key: the key to set
>>>> +#
>>>> +# @value: The data to set the key to
>>>> +#
>>>> +# @format: #optional value encoding (default 'utf8').
>>>> +#          - base64: value is assumed to be base64 encoded text.  Its binary
>>>> +#            decoding gets set.
>>> Shouldn't you copy ringbuf-write's bug note?
>>>
>>>      #            Bug: invalid base64 is currently not rejected.
>>>
>> Nope.  From the cover letter:
>> ----------------------------------------------------------------------------------------
>>
>> Much more on format=base64:
>>
>> If there is a bug it is in GLIB.  However the Glib reference manual
>> refers to RFC 1421 and RFC 2045 and MIME encoding.  Based on all
>> that (which seems to match:
>>
>> http://en.wikipedia.org/wiki/Base64
>>
>> ) MIME states that all characters outside the (base64) alphabet are
>> to be ignored.  Testing shows that g_base64_decode() does this.
>>
>> The confusion is that most non-MIME uses reject a base64 string that
>> contain characters outside the alphabet.  I was just following the
>> other uses of base64 in this file.
>>
>> DataFormat refers to RFC 3548, which has the info:
>>
>> "
>>     Implementations MUST reject the encoding if it contains
>>     characters outside the base alphabet when interpreting base
>>     encoded data, unless the specification referring to this document
>>     explicitly states otherwise.  Such specifications may, as MIME
>>     does, instead state that characters outside the base encoding
>>     alphabet should simply be ignored when interpreting data ("be
>>     liberal in what you accept").
>> "
>>
>> So with GLIB going the MIME way, I do not think this is a QEMU bug
>> (you could consider this a GLIB bug, but the document I found says
>> that GLIB goes the MIME way and so does not reject anything).
>> ----------------------------------------------------------------------------------------
>>
>>
>> Based on all this, I did drop it.
> The QMP user isn't at all interested whether QEMU or GLib or any other
> library screws this up, only in what the command's specification is, and
> whatever bugs its implementation may have.
>
> We obviously have leeway with the specification.  We *can* override RFC
> 3548 by "explicitly stating otherwise".
>
> For ringbuf-write, we deliberately chose not to.  Instead we declared
> the non-rejection of invalid characters a bug.
>
> The exact same reasoning applies to your command.  If you disagree with
> the reasoning, it's certainly open to debate.

I feel that in real use (not testing) only valid base64 would be passed 
in.  However I do not want to delay this patch on this issue.


> Regardless of what consensus emerges, all uses of base64 DataFormat in
> QMP should be consistent.  Right now they aren't with your patch
> applied.

Ok, I will copy the "bug comment line" so that it is consistent.




>>>> +#          - utf8: value's UTF-8 encoding is used to set.
>>>> +#
>>>> +# Returns: Nothing on success
>>>> +#
>>>> +# Since: 2.4
>>>> +##
>>>> +{ 'command': 'vmport-guestinfo-set',
>>>> +  'data': {'key': 'str', 'value': 'str',
>>>> +           '*format': 'DataFormat'} }
>>>> +
>>>> +##
>>>> +# @VmportGuestInfoValue:
>>>> +#
>>>> +# Information about a single VMWare Tools guestinfo
>>>> +#
>>>> +# @value: The value for a key
>>>> +#
>>>> +# Since: 2.4
>>>> +##
>>>> +{ 'struct': 'VmportGuestInfoValue', 'data': {'value': 'str'} }
>>>> +
>>>> +##
>>>> +# @vmport-guestinfo-get:
>>>> +#
>>>> +# Get a VMWare Tools guestinfo value for a key
>>>> +#
>>>> +# @key: the key to get
>>> Ignorant question: is the set of keys fixed (e.g. specified by some
>>> authority), completely dynamic (i.e. whatever has been set), or
>>> something else?
>> completely dynamic
> Thanks.
>
>>>> +#
>>>> +# @format: #optional data encoding (default 'utf8').
>>>> +#          - base64: the value is returned in base64 encoding.
>>>> +#          - utf8: the value is interpreted as UTF-8.
>>>> +#
>>>> +# Returns: value for the guest info key
>>> ringbuf-read carries this bug note:
>>>
>>> #            Bug: can screw up when the buffer contains invalid UTF-8
>>> #            sequences, NUL characters, after the ring buffer lost
>>> #            data, and when reading stops because the size limit is
>>> #            reached.
>>>
>>> Doesn't it apply here, too, with "the buffer" replaced?
>> Not directly.  The best description I have so far to match the FIXME
>> would be:
>>
>> -----------------------------------------------------------------------------------
>> Bug: format=utf8 can cause QEMU to screw up (may crash) when the value
>> contains invalid UTF-8
>>
>> sequences. NUL characters will cause loss of data.
>>
>> ----------------------------------------------------------------------------------
>>
>> I have not spent the time investigating the issues with QMP and
>> invalid utf8 because it looks to be very wide spread and not just
>> restricted to this one routine.
> The problem with ringbuf-read with format=utf8 is that it attempts to
> interpret the ring buffer's contents, which could be anything, as UTF-8
> by design (not a problem), and the code doing so is insufficiently
> robust (this is the bug; patch welcome, as usual).
>
> As far as I can tell, vmport-guestinfo-get is a similar case: the value
> associated with the key could again be anything (if written with
> format=base64), and we attempt to interpret it as UTF-8 by design.
>
> What makes you think the problem is very widespread?

I only did a quick look and did not find what I would have expected.  I 
will do more looking and reply with those results.

I am happy to apply either the above Bug comment or an adjusted version 
of the ringbuf-read one for now (I have been working on getting this 
accepted for a while now, 1st posted on Fri, 30 Jan 2015 16:06:24 -0500).


    -Don Slutz

>>>> +#
>>>> +# Since: 2.4
>>>> +##
>>>> +{ 'command': 'vmport-guestinfo-get',
>>>> +  'data': {'key': 'str', '*format': 'DataFormat'},
>>>> +  'returns': 'VmportGuestInfoValue' }
>>> I gather you wrap vmport-guestinfo-get's return value in a struct for
>>> extensibility.  Can't see why and how we'd want to extend it, but better
>>> safe than sorry.
>>>
>>>> +
>>>> +##
>>>> +# @VmportGuestInfoKey:
>>>> +#
>>>> +# Information about a single VMWare Tools guestinfo
>>>> +#
>>>> +# @key: The known key
>>>> +#
>>>> +# Since: 2.4
>>>> +##
>>>> +{ 'struct': 'VmportGuestInfoKey', 'data': {'key': 'str'} }
>>>> +
>>>> +##
>>>> +# @query-vmport-guestinfo:
>>>> +#
>>>> +# Returns information about VMWare Tools guestinfo
>>>> +#
>>>> +# Returns: a list of @VmportGuestInfoKey
>>>> +#
>>>> +# Since: 2.4
>>>> +##
>>>> +{ 'command': 'query-vmport-guestinfo', 'returns': ['VmportGuestInfoKey'] }
>>> Similar.  Imagining an extension of a string key is even harder.  Okay.
>>>
>>>> +
>>>> +##
>>>>    # @set_link:
>>>>    #
>>>>    # Sets the link status of a virtual network adapter.
>>>> diff --git a/qmp-commands.hx b/qmp-commands.hx
>>>> index a05d25f..a43db8b 100644
> [...]

  reply	other threads:[~2015-07-03 21:26 UTC|newest]

Thread overview: 19+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-06-23 23:39 [Qemu-devel] [PATCH v8 0/8] Add limited support of VMware's hyper-call rpc Don Slutz
2015-06-23 23:39 ` [Qemu-devel] [PATCH v8 1/8] vmport: Switch to trace Don Slutz
2015-06-23 23:39 ` [Qemu-devel] [BUGFIX][PATCH v8 2/8] vmport: Fix vmport_cmd_ram_size Don Slutz
2015-06-23 23:39 ` [Qemu-devel] [PATCH v8 3/8] MAINTAINERS: add VMware port Don Slutz
2015-06-23 23:39 ` [Qemu-devel] [PATCH v8 4/8] vmport_rpc: Add the object vmport_rpc Don Slutz
2015-06-23 23:39 ` [Qemu-devel] [PATCH v8 5/8] vmport_rpc: Add limited support of VMware's hyper-call rpc Don Slutz
2015-06-23 23:39 ` [Qemu-devel] [PATCH v8 7/8] vmport_rpc: Add migration Don Slutz
2015-06-23 23:39 ` [Qemu-devel] [PATCH v8 8/8] vmport: Add VMware all ring hack Don Slutz
2015-07-01  6:50   ` Michael S. Tsirkin
2015-07-03 13:08     ` Don Slutz
2015-07-03 13:50       ` Paolo Bonzini
2015-07-05  6:40         ` Michael S. Tsirkin
2015-07-29 15:25           ` Don Slutz
2015-06-30 18:16 ` [Qemu-devel] [ping][PATCH v8 0/8] Add limited support of VMware's hyper-call rpc Don Slutz
     [not found] ` <1435102773-3498-7-git-send-email-Don.Slutz@Gmail.com>
2015-07-02 14:11   ` [Qemu-devel] [PATCH v8 6/8] vmport_rpc: Add QMP access to vmport_rpc object Markus Armbruster
2015-07-03 16:53     ` Don Slutz
2015-07-03 17:56       ` Markus Armbruster
2015-07-03 21:26         ` Don Slutz [this message]
2015-07-04  7:00           ` Markus Armbruster

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=5596FDF2.1060702@Gmail.com \
    --to=don.slutz@gmail.com \
    --cc=afaerber@suse.de \
    --cc=aliguori@amazon.com \
    --cc=armbru@redhat.com \
    --cc=dslutz@verizon.com \
    --cc=lcapitulino@redhat.com \
    --cc=mst@redhat.com \
    --cc=pbonzini@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=rth@twiddle.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).