<div dir="ltr">Incremental patches do look better. Just to make sure I am on the right track, I have some queries.<div><br><div>I have to apply the changes one function at a time, and these changes will be the same ones I made in the v2 and v3 patches, right?</div></div><div>If that is the case, do I need the next patch to be v4 or can the series of patches start from v1?</div><div>I can start afresh with the patches and this might save some confusion later.</div><div><br></div><div>Thanks.</div></div><div class="gmail_extra"><br><div class="gmail_quote">On Wed, Apr 11, 2018 at 3:52 AM, John Ferlan <span dir="ltr"><<a href="mailto:jferlan@redhat.com" target="_blank">jferlan@redhat.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class=""><br>
<br>
On 04/02/2018 04:17 PM, Sukrit Bhatnagar wrote:<br>
> This patch adds virQEMUBuildBufferEscapeComma to properly<br>
> escape commas in user provided data fields for qemu command<br>
> line processing.<br>
><br>
> Signed-off-by: Sukrit Bhatnagar <<a href="mailto:skrtbhtngr@gmail.com">skrtbhtngr@gmail.com</a>><br>
> ---<br>
><br>
> Thank you for the helpful feedback and apologies for the delay.<br>
<br>
</span>Well we all get busy and delayed by other things! It's been a week since<br>
you posted and well, I know I'm behind doing reviews!<br>
<br>
Nice on the using the --- for your adjustments and the issue you discovered.<br>
<br>
What happened to the changes from your previous version? They don't seem<br>
to be included in this patch and they weren't pushed upstream. This<br>
patch is all new changes.<br>
<br>
The "next" step is to attempt to generate patches that make incremental<br>
progress towards the end goal. Not all your changes need to go in one<br>
pile especially if something is separable - there's a methodology one<br>
develops over time. Changes don't need to be "so separated" that you get<br>
very large series, but you can create smaller patches, altering single<br>
API's/helpers and adjusting anything called by them to handle the<br>
changes. Some times it's a changed result and other times it's doing<br>
nothing because the patch fixes something. Again, it's one of those over<br>
time things.<br>
<br>
In this case, almost every function could have had it's own patch. That<br>
way a reviewer can ACK/Reviewed-by and push part of the series while<br>
perhaps asking for respins on other parts. It also allows for a NACK of<br>
a specific area. Much easier to change and review smaller things too!<br>
<br>
Since this is a GSOC type activity I won't "do" the work for you, but I<br>
will help "guide" you to the answer. First things first - hopefully you<br>
haven't lost your original patch. It's easily recreateable at least. We<br>
will start easy/slow... Using that patch as a starting point, create a<br>
series of 5 patches<br>
<br>
 patch 1: Changes for qemuBuildRomStr<br>
 patch 2: Changes for qemuBuildDriveDevStr<br>
 patch 3: Changes for qemuBuildFSStr and qemuBuildFSDevStr<br>
 patch 4: Changes for qemuBuildGraphicsVNCCommandLin<wbr>e<br>
 patch 5: Changes for qemuBuildDomainLoaderCommandLi<wbr>ne<br>
<br>
Hold onto the changes for qemuBuildHostNetStr,<br>
qemuBuildChrChardevFileStr, qemuBuildChrChardevStr, and<br>
qemuBuildGraphicsSPICECommandL<wbr>ine as they'll be combined with separated<br>
patches from this patch.<br>
<br>
Post the above 5 - I've included patch 1 & 2 for you as an attachment to<br>
this reply so you can see the format... It should be fairly easy to copy<br>
from there and post as a v4.<br>
<br>
Once you've done that - work through the rest of this using similar<br>
context - although a few of these will be a bit larger and more<br>
complicated (especially the first one for build network drive.<br>
<div><div class="h5"><br>
><br>
> Changes in v3:<br>
> virQEMUBuildBufferEscapeComma was applied to:<br>
> - src->hosts->socket in qemuBuildNetworkDriveURI<br>
> - src->path, src->configFile in qemuBuildNetworkDriveStr<br>
> - disk->blkdeviotune.group_name in qemuBuildDiskThrottling<br>
> - net->data.socket.address, net->data.socket.localaddr in<br>
>   qemuBuildHostNetStr<br>
> - dev->data.file.path in qemuBuildChrChardevStr<br>
> - graphics->data.spice.<wbr>rendernode in<br>
>   qemuBuildGraphicsSPICECommandL<wbr>ine<br>
> - smartcard->data.cert.file[i], smartcard->data.cert.database in<br>
>   qemuBuildSmartcardCommandLine<br>
><br>
> Changes in v2:<br>
> virQEMUBuildBufferEscapeComma was applied to:<br>
> - info->romfile in qemuBuildRomStr<br>
> - disk->vendor, disk->product in qemuBuildDriveDevStr<br>
> - fs->src->path in qemuBuildFSStr<br>
> - fs->dst in qemuBuildFSDevStr<br>
> - connect= in qemuBuildHostNetStr<br>
> - fileval handling in qemuBuildChrChardevStr<br>
> - TYPE_DEV, TYPE_PIPE handling in qemuBuildChrChardevStr<br>
> - cfg->vncTLSx509certdir in qemuBuildGraphicsVNCCommandLin<wbr>e<br>
> - cfg->spiceTLSx509certdir in qemuBuildGraphicsSPICECommandL<wbr>ine<br>
> - loader->path, loader->nvram usage in<br>
>   qemuBuildDomainLoaderCommandLi<wbr>ne<br>
><br>
> Link to v2: <a href="https://www.redhat.com/archives/libvir-list/2018-March/msg00965.html" rel="noreferrer" target="_blank">https://www.redhat.com/<wbr>archives/libvir-list/2018-<wbr>March/msg00965.html</a><br>
><br>
><br>
> When I tried to change src->path in qemuBuildNetworkDriveStr<br>
> for this portion<br>
><br>
> 961             } else if (src->nhosts == 1) {<br>
> 962                 if (virAsprintf(&ret, "sheepdog:%s:%u:%s",<br>
> 963                                 src->hosts->name, src->hosts->port,<br>
> 964                                 src->path) < 0)<br>
> 965                     goto cleanup;<br>
> 966             } else {<br>
><br>
> make check reported the following error.<br>
><br>
> 141) QEMU XML-2-ARGV disk-drive-network-sheepdog                       ...<br>
> In '/home/skrtbhtngr/libvirt/<wbr>tests/qemuxml2argvdata/disk-<wbr>drive-network-sheepdog.args':<br>
> Offset 0<br>
> Expect [LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test QEMU_AUDIO_DRV=none /usr/bin/qemu-system-i686 -name QEMUGuest1 -S -M pc -m 214 -smp 1,sockets=1,cores=1,threads=1 -uuid c7a5fdbd-edaf-9455-926a-<wbr>d65c16db1809 -nographic -nodefaults -chardev socket,id=charmonitor,path=/<wbr>tmp/lib/domain--1-QEMUGuest1/<wbr>monitor.sock,server,nowait -mon chardev=charmonitor,id=<wbr>monitor,mode=readline -no-acpi -boot c -usb -drive file=/dev/HostVG/QEMU,,Guest,,<wbr>,,1,format=raw,if=none,id=<wbr>drive-ide0-0-0 -device ide-drive,bus=ide.0,unit=0,<wbr>drive=drive-ide0-0-0,id=ide0-<wbr>0-0 -drive file=sheepdog:<a href="http://example.org:6000">example.org:6000</a><wbr>:image,,with,,commas,format=<wbr>raw,if=none,id=drive-virtio-<wbr>disk0 -device virtio-blk-pci,bus=pci.0,addr=<wbr>0x3,drive=drive-virtio-disk0,<wbr>id=virtio-disk0<br>
> ]<br>
> Actual [LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test QEMU_AUDIO_DRV=none /usr/bin/qemu-system-i686 -name QEMUGuest1 -S -M pc -m 214 -smp 1,sockets=1,cores=1,threads=1 -uuid c7a5fdbd-edaf-9455-926a-<wbr>d65c16db1809 -nographic -nodefaults -chardev socket,id=charmonitor,path=/<wbr>tmp/lib/domain--1-QEMUGuest1/<wbr>monitor.sock,server,nowait -mon chardev=charmonitor,id=<wbr>monitor,mode=readline -no-acpi -boot c -usb -drive file=/dev/HostVG/QEMU,,Guest,,<wbr>,,1,format=raw,if=none,id=<wbr>drive-ide0-0-0 -device ide-drive,bus=ide.0,unit=0,<wbr>drive=drive-ide0-0-0,id=ide0-<wbr>0-0 -drive file=sheepdog:<a href="http://example.org:6000">example.org:6000</a><wbr>:image,,,,with,,,,commas,<wbr>format=raw,if=none,id=drive-<wbr>virtio-disk0 -device virtio-blk-pci,bus=pci.0,addr=<wbr>0x3,drive=drive-virtio-disk0,<wbr>id=virtio-disk0<br>
> ]<br>
>                                                                       ... FAILED<br>
><br>
><br>
> In disk-drive-network-sheepdog.<wbr>args:<br>
>     ...<br>
>     -drive file=sheepdog:<a href="http://example.org:6000">example.org:6000</a><wbr>:image,,with,,commas,format=<wbr>raw,if=none,\<br>
>     ...<br>
><br>
> I was not quite sure how to handle this part. Adding<br>
> virQEMUBuildBufferEscapeComma there is escaping the twin commas<br>
> in the file name again. I have left that part unchanged.<br>
><br>
<br>
</div></div>This is because qemuBuildDriveSourceStr calls qemuGetDriveSourceString<br>
which calls qemuBuildNetworkDriveStr returning @source. Then back in<br>
qemuBuildDriveSourceStr the @source goes through another transformation:<br>
<br>
    if (source) {<br>
        virBufferAddLit(buf, "file=");<br>
...<br>
        virQEMUBuildBufferEscapeComma(<wbr>buf, source);<br>
...<br>
<br>
Because the return from qemuBuildNetworkDriveStr is used by callers that<br>
don't expect qemuGetDriveSourceString to return a comma escaped string<br>
that means adding a bit of logic so that qemuBuildNetworkDriveURI and<br>
qemuBuildNetworkDriveStr can escape only when necessary.<br>
<br>
Returning an escaped string for qemuDomainSnapshotCreateSingle<wbr>DiskActive<br>
would not be a good thing.<br>
<br>
Still it's a *good thing* you've gone through this exercise *and* made<br>
note of what you saw. It makes it clearer what the "right" path is for<br>
me at least. Of course if you'd separated out your patches it would make<br>
resolving it a bit easier!<br>
<br>
Also, this exercise has shown there's a bug in how the command line is<br>
built for hostdev's. The source is not escaped, although I doubt we'd<br>
get an iSCSI tgt/lun with a "rogue" comma - it's just not expected.<br>
Still who knows, we still need to handle it.<br>
<span class=""><br>
><br>
> src/qemu/qemu_command.c | 111 +++++++++++++++++++++++++-----<wbr>------------------<br>
>  1 file changed, 59 insertions(+), 52 deletions(-)<br>
><br>
> diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c<br>
> index 6f76f18ab..26b36551c 100644<br>
> --- a/src/qemu/qemu_command.c<br>
> +++ b/src/qemu/qemu_command.c<br>
> @@ -844,14 +844,18 @@ qemuBuildNetworkDriveURI(<wbr>virStorageSourcePtr src,<br>
>                           qemuDomainSecretInfoPtr secinfo)<br>
<br>
</span>I think a third parameter "bool escape" will be necessary...<br>
<span class=""><br>
>  {<br>
>      virURIPtr uri = NULL;<br>
> -    char *ret = NULL;<br>
> +    char *ret = NULL, *socket = NULL;<br>
<br>
</span>There is a general preference for one argument per line.<br>
<span class=""><br>
> +    virBuffer buf = VIR_BUFFER_INITIALIZER;<br>
><br>
>      if (!(uri = qemuBlockStorageSourceGetURI(<wbr>src)))<br>
>          goto cleanup;<br>
><br>
> -    if (src->hosts->socket &&<br>
> -        virAsprintf(&uri->query, "socket=%s", src->hosts->socket) < 0)<br>
> -        goto cleanup;<br>
> +    if (src->hosts->socket) {<br>
> +        virQEMUBuildBufferEscapeComma(<wbr>&buf, src->hosts->socket);<br>
> +        socket = virBufferContentAndReset(&buf)<wbr>;<br>
> +        if (virAsprintf(&uri->query, "socket=%s", socket) < 0)<br>
> +            goto cleanup;<br>
> +    }<br>
<br>
</span>This logic needs to be separated into "if (escape)" escape the socket, e.g.:<br>
<br>
    if (src->hosts->socket) {<br>
        if (escape) {<br>
            virQEMUBuildBufferEscapeComma(<wbr>&buf, src->hosts->socket);<br>
            socket = virBufferContentAndReset(&buf)<wbr>;<br>
<span class="">        }<br>
        if (virAsprintf(&uri->query, "socket=%s",<br>
</span>                        socket ? socket : src->hosts->socket) < 0)<br>
            goto cleanup;<br>
<span class="">    }<br>
<br>
><br>
>      if (qemuBuildGeneralSecinfoURI(<wbr>uri, secinfo) < 0)<br>
>          goto cleanup;<br>
> @@ -860,6 +864,8 @@ qemuBuildNetworkDriveURI(<wbr>virStorageSourcePtr src,<br>
><br>
>   cleanup:<br>
>      virURIFree(uri);<br>
> +    virBufferFreeAndReset(&buf);<br>
> +<br>
<br>
</span>The virBufferContentAndReset will reinitialize the buffer, so no need<br>
for this call, but we would leak @socket possibly, so that does need to<br>
be freed.... Also, need for extra blank line here.  This then is just:<br>
<br>
    VIR_FREE(socket);<br>
<span class=""><br>
>      return ret;<br>
>  }<br>
><br>
> @@ -868,8 +874,9 @@ static char *<br>
>  qemuBuildNetworkDriveStr(<wbr>virStorageSourcePtr src,<br>
>                           qemuDomainSecretInfoPtr secinfo)<br>
<br>
</span>I think a third parameter "bool escape" will be necessary...<br>
<span class=""><br>
>  {<br>
> -    char *ret = NULL;<br>
> +    char *ret = NULL, *path = NULL, *file = NULL;<br>
<br>
</span>again, one line and we should only need one, e.g. 'tmp' - since we know<br>
it's initialized to NULL we can use that when deciding whether we escape<br>
or not.<br>
<span class=""><br>
>      virBuffer buf = VIR_BUFFER_INITIALIZER;<br>
> +    virBuffer bufTemp = VIR_BUFFER_INITIALIZER;<br>
>      size_t i;<br>
><br>
>      switch ((virStorageNetProtocol) src->protocol) {<br>
> @@ -914,8 +921,10 @@ qemuBuildNetworkDriveStr(<wbr>virStorageSourcePtr src,<br>
>                      goto cleanup;<br>
>                  }<br>
><br>
> -                if (src->path)<br>
> -                    virBufferAsprintf(&buf, ":exportname=%s", src->path);<br>
> +                if (src->path) {<br>
> +                    virBufferAddLit(&buf, ":exportname=");<br>
> +                    virQEMUBuildBufferEscapeComma(<wbr>&buf, src->path);<br>
> +                }<br>
<br>
</span>        if (src->path) {<br>
            if (escape) {<br>
                virBufferAddLit(&buf, ":exportname=");<br>
                virQEMUBuildBufferEscapeComma(<wbr>&buf, src->path);<br>
            } else {<br>
<span class="">                virBufferAsprintf(&buf, ":exportname=%s", src->path);<br>
            }<br>
        }<br>
<br>
><br>
</span><span class="">>                  if (virBufferCheckError(&buf) < 0)<br>
>                      goto cleanup;<br>
> @@ -945,7 +954,9 @@ qemuBuildNetworkDriveStr(<wbr>virStorageSourcePtr src,<br>
>              }<br>
><br>
>              if (src->nhosts == 0) {<br>
> -                if (virAsprintf(&ret, "sheepdog:%s", src->path) < 0)<br>
> +                virQEMUBuildBufferEscapeComma(<wbr>&bufTemp, src->path);<br>
> +                path = virBufferContentAndReset(&<wbr>bufTemp);<br>
> +                if (virAsprintf(&ret, "sheepdog:%s", path) < 0)<br>
>                      goto cleanup;<br>
>              } else if (src->nhosts == 1) {<br>
>                  if (virAsprintf(&ret, "sheepdog:%s:%u:%s",<br>
<br>
</span>    if (escape) {<br>
        virQEMUBuildBufferEscapeComma(<wbr>&bufTemp, src->path);<br>
        tmp = virBufferContentAndReset(&<wbr>bufTemp);<br>
<span class="">    }<br>
    if (src->nhosts == 0) {<br>
</span>        if (virAsprintf(&ret, "sheepdog:%s", tmp ? tmp : src->path) < 0)<br>
<span class="">            goto cleanup;<br>
    } else if (src->nhosts == 1) {<br>
        if (virAsprintf(&ret, "sheepdog:%s:%u:%s",<br>
</span><span class="">                        src->hosts->name, src->hosts->port,<br>
</span>                        tmp ? tmp : src->path) < 0)<br>
            goto cleanup;<br>
    } else {<br>
<br>
<br>
NB: In your patch - if the .xml/.args file hadn't used a host w/ a path<br>
having a comma, then that would have failed.<br>
<br>
IOW: if tests/qemuxml2argdata/disk-<wbr>drive-network-sheepdog.xml:<br>
<br>
    <disk type='network' device='disk'><br>
      <driver name='qemu' type='raw'/><br>
      <source protocol='sheepdog' name='image,with,commas'><br>
        <host name='<a href="http://example.org" rel="noreferrer" target="_blank">example.org</a>' port='6000'/><br>
      </source><br>
      <target dev='vda' bus='virtio'/><br>
    </disk><br>
<br>
was:<br>
<br>
    <disk type='network' device='disk'><br>
      <driver name='qemu' type='raw'/><br>
      <source protocol='sheepdog' name='image,with,commas'/><br>
      <target dev='vda' bus='virtio'/><br>
    </disk><br>
<br>
then tests/qemuxml2argvdata/disk-<wbr>drive-network-sheepdog.args would<br>
change from:<br>
<span class=""><br>
-drive<br>
file=sheepdog:<a href="http://example.org:6000">example.org:6000</a><wbr>:image,,with,,commas,format=<wbr>raw,if=none,\<br>
</span>id=drive-virtio-disk0 \<br>
<br>
to (something like):<br>
<br>
-drive file=sheepdog:image,,with,,<wbr>commas,format=raw,if=none,\<br>
id=drive-virtio-disk0 \<br>
<br>
But with your change it would have had the 4 commas (hopefully this<br>
makes sense).<br>
<span class=""><br>
<br>
> @@ -967,8 +978,9 @@ qemuBuildNetworkDriveStr(<wbr>virStorageSourcePtr src,<br>
>                                 src->path);<br>
>                  goto cleanup;<br>
>              }<br>
> -<br>
> -            virBufferStrcat(&buf, "rbd:", src->volume, "/", src->path, NULL);<br>
> +            virQEMUBuildBufferEscapeComma(<wbr>&bufTemp, src->path);<br>
> +            path = virBufferContentAndReset(&<wbr>bufTemp);<br>
> +            virBufferStrcat(&buf, "rbd:", src->volume, "/", path, NULL);<br>
<br>
</span>        if (escape) {<br>
            virQEMUBuildBufferEscapeComma(<wbr>&bufTemp, src->path);<br>
            tmp = virBufferContentAndReset(&<wbr>bufTemp);<br>
<span class="">        }<br>
        virBufferStrcat(&buf, "rbd:", src->volume, "/",<br>
</span>                        tmp ? tmp : src->path, NULL);<br>
        VIR_FREE(tmp);<br>
<span class=""><br>
><br>
>              if (src->snapshot)<br>
>                  virBufferEscape(&buf, '\\', ":", "@%s", src->snapshot);<br>
> @@ -994,8 +1006,11 @@ qemuBuildNetworkDriveStr(<wbr>virStorageSourcePtr src,<br>
>                  }<br>
>              }<br>
><br>
> -            if (src->configFile)<br>
> -                virBufferEscape(&buf, '\\', ":", ":conf=%s", src->configFile);<br>
> +            if (src->configFile) {<br>
> +                virQEMUBuildBufferEscapeComma(<wbr>&bufTemp, src->configFile);<br>
> +                file = virBufferContentAndReset(&<wbr>bufTemp);<br>
> +                virBufferEscape(&buf, '\\', ":", ":conf=%s", file);<br>
> +            }<br>
<br>
</span>    if (src->configFile) {<br>
        if (escape) {<br>
            virQEMUBuildBufferEscapeComma(<wbr>&bufTemp, src->configFile);<br>
            tmp = virBufferContentAndReset(&<wbr>bufTemp);<br>
<span class="">        }<br>
        virBufferEscape(&buf, '\\', ":", ":conf=%s",<br>
</span>                        tmp ? tmp : src->configFile);<br>
<span class="">    }<br>
<br>
><br>
>              if (virBufferCheckError(&buf) < 0)<br>
>                  goto cleanup;<br>
> @@ -1022,6 +1037,7 @@ qemuBuildNetworkDriveStr(<wbr>virStorageSourcePtr src,<br>
>      }<br>
><br>
>   cleanup:<br>
> +    virBufferFreeAndReset(&<wbr>bufTemp);<br>
<br>
</span>Again, each of the callers used virBufferContentAndReset, so the @path<br>
and @file arguments would have been needed to be VIR_FREE'd instead.<br>
However, if you take my suggestion w/ a tmp variable, then you just<br>
VIR_FREE(tmp) instead.<br>
<br>
>      virBufferFreeAndReset(&buf);<br>
><br>
>      return ret;<br>
<br>
When you post your next patch - use this opportunity to separate out<br>
these two functions into their own patch (along with adjustments to<br>
callers to pass the escape bool.  This will be the most complex patch<br>
out of them all.<br>
<span class=""><br>
> @@ -1630,6 +1646,8 @@ qemuBuildDiskThrottling(<wbr>virDomainDiskDefPtr disk,<br>
>          virBufferAsprintf(buf, ",throttling." _label "=%llu", \<br>
>                            disk->blkdeviotune._field); \<br>
>      }<br>
> +    virBuffer bufTemp = VIR_BUFFER_INITIALIZER;<br>
> +    char *name = NULL;<br>
<br>
</span>These can move to ...<br>
<span class=""><br>
><br>
>      IOTUNE_ADD(total_bytes_sec, "bps-total");<br>
>      IOTUNE_ADD(read_bytes_sec, "bps-read");<br>
> @@ -1647,8 +1665,9 @@ qemuBuildDiskThrottling(<wbr>virDomainDiskDefPtr disk,<br>
><br>
>      IOTUNE_ADD(size_iops_sec, "iops-size");<br>
>      if (disk->blkdeviotune.group_<wbr>name) {<br>
<br>
</span>... here (IOW: localize them more).<br>
<span class=""><br>
> -        virBufferEscapeString(buf, ",throttling.group=%s",<br>
> -                              disk->blkdeviotune.group_name)<wbr>;<br>
> +        virQEMUBuildBufferEscapeComma(<wbr>&bufTemp, disk->blkdeviotune.group_name)<wbr>;<br>
> +        name = virBufferContentAndReset(&<wbr>bufTemp);<br>
> +        virBufferEscapeString(buf, ",throttling.group=%s", name);<br>
<br>
</span>    VIR_FREE(name);<br>
<span class=""><br>
>      }<br>
><br>
>      IOTUNE_ADD(total_bytes_sec_<wbr>max_length, "bps-total-max-length");<br>
> @@ -1657,6 +1676,8 @@ qemuBuildDiskThrottling(<wbr>virDomainDiskDefPtr disk,<br>
>      IOTUNE_ADD(total_iops_sec_max_<wbr>length, "iops-total-max-length");<br>
>      IOTUNE_ADD(read_iops_sec_max_<wbr>length, "iops-read-max-length");<br>
>      IOTUNE_ADD(write_iops_sec_max_<wbr>length, "iops-write-max-length");<br>
> +<br>
> +    virBufferFreeAndReset(&<wbr>bufTemp);<br>
<br>
</span>NB: virBufferContentAndReset will be all you need for bufTemp, but @name<br>
is leaked, but that's adjusted above<br>
<br>
>  #undef IOTUNE_ADD<br>
>  }<br>
><br>
<br>
The changes for qemuBuildDiskThrottling should be in one patch.<br>
<span class=""><br>
> @@ -3651,27 +3672,25 @@ qemuBuildHostNetStr(<wbr>virDomainNetDefPtr net,<br>
>          break;<br>
><br>
>      case VIR_DOMAIN_NET_TYPE_SERVER:<br>
> -        virBufferAsprintf(&buf, "socket%clisten=%s:%d,",<br>
> -                          type_sep,<br>
> +        virBufferAsprintf(&buf, "socket%clisten=", type_sep);<br>
> +        virQEMUBuildBufferEscapeComma(<wbr>&buf,<br>
>                            net->data.socket.address ? net->data.socket.address<br>
> -                          : "",<br>
> -                          net->data.socket.port);<br>
> +                          : "");<br>
<br>
</span>This has alignment issues w/ the previous line.<br>
<br>
It also points out something I'm not sure whether it's a bug or not.  If<br>
net->data.socket.address == NULL, then the command line would be (from<br>
net-vhostuser.args):<br>
<br>
    -netdev socket,listen=:2015,<br>
<br>
But that looks strange to me, I guess I'd expect:<br>
<br>
    -netdev socket,listen="":2015,<br>
<br>
Still the former syntax works so I suppose it's OK.<br>
<br>
Still changes could be rewritten as:<br>
<br>
    virBufferAsprintf(&buf, "socket%clisten=", type_sep);<br>
    virQEMUBuildBufferEscapeComma(<wbr>&buf, net->data.socket.address);<br>
<span class="">    virBufferAsprintf(&buf, ":%d,", net->data.socket.port);<br>
<br>
</span>BTW: Your previous patch added a couple of changes to this API - they<br>
should be moved into here so that we have all the adjustments to<br>
qemuBuildHostNetStr in one patch.<br>
<div><div class="h5"><br>
> +        virBufferAsprintf(&buf, ":%d,", net->data.socket.port);<br>
>          break;<br>
><br>
>      case VIR_DOMAIN_NET_TYPE_MCAST:<br>
> -        virBufferAsprintf(&buf, "socket%cmcast=%s:%d,",<br>
> -                          type_sep,<br>
> -                          net->data.socket.address,<br>
> -                          net->data.socket.port);<br>
> +        virBufferAsprintf(&buf, "socket%cmcast=", type_sep);<br>
> +        virQEMUBuildBufferEscapeComma(<wbr>&buf, net->data.socket.address);<br>
> +        virBufferAsprintf(&buf, ":%d,", net->data.socket.port);<br>
>          break;<br>
><br>
>      case VIR_DOMAIN_NET_TYPE_UDP:<br>
> -        virBufferAsprintf(&buf, "socket%cudp=%s:%d,localaddr=%<wbr>s:%d,",<br>
> -                          type_sep,<br>
> -                          net->data.socket.address,<br>
> -                          net->data.socket.port,<br>
> -                          net->data.socket.localaddr,<br>
> -                          net->data.socket.localport);<br>
> +        virBufferAsprintf(&buf, "socket%cudp=", type_sep);<br>
> +        virQEMUBuildBufferEscapeComma(<wbr>&buf, net->data.socket.address);<br>
> +        virBufferAsprintf(&buf, ":%d,localaddr=", net->data.socket.port);<br>
> +        virQEMUBuildBufferEscapeComma(<wbr>&buf, net->data.socket.localaddr);<br>
> +        virBufferAsprintf(&buf, ":%d,", net->data.socket.localport);<br>
>          break;<br>
><br>
>      case VIR_DOMAIN_NET_TYPE_USER:<br>
<br>
</div></div>And like noted before - the above hunk can be it's own patch!<br>
<span class=""><br>
> @@ -4954,9 +4973,10 @@ qemuBuildChrChardevStr(<wbr>virLogManagerPtr logManager,<br>
>                         bool chardevStdioLogd)<br>
>  {<br>
>      virBuffer buf = VIR_BUFFER_INITIALIZER;<br>
> +    virBuffer bufTemp = VIR_BUFFER_INITIALIZER;<br>
>      bool telnet;<br>
>      char *charAlias = NULL;<br>
> -    char *ret = NULL;<br>
> +    char *ret = NULL, *path = NULL;<br>
<br>
</span>One line per argument...<br>
<span class=""><br>
><br>
>      if (!(charAlias = qemuAliasChardevFromDevAlias(<wbr>alias)))<br>
>          goto cleanup;<br>
> @@ -4990,9 +5010,11 @@ qemuBuildChrChardevStr(<wbr>virLogManagerPtr logManager,<br>
>                             _("append not supported in this QEMU binary"));<br>
>              goto cleanup;<br>
>          }<br>
> +        virQEMUBuildBufferEscapeComma(<wbr>&bufTemp, dev->data.file.path);<br>
> +        path = virBufferContentAndReset(&<wbr>bufTemp);<br>
>          if (qemuBuildChrChardevFileStr(<wbr>chardevStdioLogd ? logManager : NULL,<br>
>                                         cmd, def, &buf,<br>
> -                                       "path", dev->data.file.path,<br>
> +                                       "path", path,<br>
>                                         "append", dev->data.file.append) < 0)<br>
<br>
</span>path is leaked.<br>
<br>
>              goto cleanup;<br>
>          break;<br>
<br>
And the above is in it's own patch.  Here again, I'd combine the changes<br>
from your original patch to qemuBuildChrChardevStr into this one. I'd<br>
also include the changes for qemuBuildChrChardevFileStr within the same<br>
patch since they are "related".<br>
<span class=""><br>
> @@ -8150,8 +8172,8 @@ qemuBuildGraphicsSPICECommandL<wbr>ine(virQEMUDriverConfigPtr cfg,<br>
>                                 _("This QEMU doesn't support spice OpenGL rendernode"));<br>
>                  goto error;<br>
>              }<br>
> -<br>
> -            virBufferAsprintf(&opt, "rendernode=%s,", graphics->data.spice.<wbr>rendernode);<br>
> +            virBufferAddLit(&opt, "rendernode=");<br>
> +            virQEMUBuildBufferEscapeComma(<wbr>&opt, graphics->data.spice.<wbr>rendernode);<br>
>          }<br>
>      }<br>
><br>
<br>
</span>The above can be it's own patch and of course include the SPICE change<br>
from your original patch too.<br>
<div><div class="h5"><br>
> @@ -8771,7 +8793,6 @@ qemuBuildSmartcardCommandLine(<wbr>virLogManagerPtr logManager,<br>
>      virDomainSmartcardDefPtr smartcard;<br>
>      char *devstr;<br>
>      virBuffer opt = VIR_BUFFER_INITIALIZER;<br>
> -    const char *database;<br>
>      const char *contAlias = NULL;<br>
><br>
>      if (!def->nsmartcards)<br>
> @@ -8814,29 +8835,15 @@ qemuBuildSmartcardCommandLine(<wbr>virLogManagerPtr logManager,<br>
><br>
>          virBufferAddLit(&opt, "ccid-card-emulated,backend=<wbr>certificates");<br>
>          for (i = 0; i < VIR_DOMAIN_SMARTCARD_NUM_<wbr>CERTIFICATES; i++) {<br>
> -            if (strchr(smartcard->data.cert.<wbr>file[i], ',')) {<br>
> -                virBufferFreeAndReset(&opt);<br>
> -                virReportError(VIR_ERR_CONFIG_<wbr>UNSUPPORTED,<br>
> -                               _("invalid certificate name: %s"),<br>
> -                               smartcard->data.cert.file[i]);<br>
> -                return -1;<br>
> -            }<br>
> -            virBufferAsprintf(&opt, ",cert%zu=%s", i + 1,<br>
> -                              smartcard->data.cert.file[i]);<br>
> +            virBufferAsprintf(&opt, ",cert%zu=", i + 1);<br>
> +            virQEMUBuildBufferEscapeComma(<wbr>&opt, smartcard->data.cert.file[i]);<br>
>          }<br>
>          if (smartcard->data.cert.<wbr>database) {<br>
> -            if (strchr(smartcard->data.cert.<wbr>database, ',')) {<br>
> -                virBufferFreeAndReset(&opt);<br>
> -                virReportError(VIR_ERR_CONFIG_<wbr>UNSUPPORTED,<br>
> -                               _("invalid database name: %s"),<br>
> -                               smartcard->data.cert.database)<wbr>;<br>
> -                return -1;<br>
> -            }<br>
> -            database = smartcard->data.cert.database;<br>
> +            virBufferAddLit(&opt, ",db=");<br>
> +            virQEMUBuildBufferEscapeComma(<wbr>&opt, smartcard->data.cert.database)<wbr>;<br>
>          } else {<br>
> -            database = VIR_DOMAIN_SMARTCARD_DEFAULT_<wbr>DATABASE;<br>
> +            virBufferAsprintf(&opt, ",db=%s", VIR_DOMAIN_SMARTCARD_DEFAULT_<wbr>DATABASE);<br>
>          }<br>
> -        virBufferAsprintf(&opt, ",db=%s", database);<br>
>          break;<br>
><br>
>      case VIR_DOMAIN_SMARTCARD_TYPE_<wbr>PASSTHROUGH:<br>
><br>
<br>
</div></div>And this one gets it's own patch too.<br>
<br>
In the end, probably 11 patches total. Do the easy ones first. It's<br>
always good to make some progress and have some success rather than<br>
having to redo everything all over again and have this large pile of a<br>
singlular change waiting for some part of it to be fixed.  Once<br>
everything is done we can remove the entry from bite sized tasks.<br>
<span class="HOEnZb"><font color="#888888"><br>
John<br>
</font></span></blockquote></div><br></div>