[libvirt] [PATCH 1/2] virsh: make ,, escape parsing common

Peter Krempa pkrempa at redhat.com
Wed Nov 7 11:13:40 UTC 2012


On 11/07/12 06:41, Doug Goldstein wrote:
> On Tue, Nov 6, 2012 at 10:00 PM, Eric Blake <eblake at redhat.com> wrote:
>> So far, none of the existing callers of vshStringToArray expected
>> the user to ever pass a literal comma; meanwhile, snapshot parsing
>> had rolled its own array parser.  Moving the comma escaping into
>> the common function won't affect any existing callers, and will make
>> this function reusable for adding memory handling to snapshot parsing.
>>
>> As a bonus, the testsuite was already testing snapshot parsing, so
>> the fact that the test still passes means that we are now giving
>> testsuite exposure to vshStringToArray.
>>
>> * tools/virsh-snapshot.c (vshParseSnapshotDiskspec): Move ,,
>> parsing...
>> * tools/virsh.c (vshStringToArray): ...into common function.
>> Also, vshStrdup can't fail.
>> ---
>>   tools/virsh-snapshot.c | 50 ++++++++++++++++++++++-------------------------
>>   tools/virsh.c          | 53 ++++++++++++++++++++++++++++++--------------------
>>   2 files changed, 55 insertions(+), 48 deletions(-)
>>
>> diff --git a/tools/virsh-snapshot.c b/tools/virsh-snapshot.c
>> index 818ef56..159f577 100644
>> --- a/tools/virsh-snapshot.c
>> +++ b/tools/virsh-snapshot.c
>> @@ -197,33 +197,26 @@ static int
>>   vshParseSnapshotDiskspec(vshControl *ctl, virBufferPtr buf, const char *str)
>>   {
>>       int ret = -1;
>> -    char *name = NULL;
>> -    char *snapshot = NULL;
>> -    char *driver = NULL;
>> -    char *file = NULL;
>> -    char *spec = vshStrdup(ctl, str);
>> -    char *tmp = spec;
>> -    size_t len = strlen(str);
>> -
>> -    if (*str == ',')
>> +    const char *name = NULL;
>> +    const char *snapshot = NULL;
>> +    const char *driver = NULL;
>> +    const char *file = NULL;
>> +    char **array = NULL;
>> +    int narray;
>> +    int i;
>> +
>> +    narray = vshStringToArray(str, &array);
>> +    if (narray <= 0)
>>           goto cleanup;
>> -    name = tmp;
>> -    while ((tmp = strchr(tmp, ','))) {
>> -        if (tmp[1] == ',') {
>> -            /* Recognize ,, as an escape for a literal comma */
>> -            memmove(&tmp[1], &tmp[2], len - (tmp - spec) - 2 + 1);
>> -            len--;
>> -            tmp++;
>> -            continue;
>> -        }
>> -        /* Terminate previous string, look for next recognized one */
>> -        *tmp++ = '\0';
>> -        if (!snapshot && STRPREFIX(tmp, "snapshot="))
>> -            snapshot = tmp + strlen("snapshot=");
>> -        else if (!driver && STRPREFIX(tmp, "driver="))
>> -            driver = tmp + strlen("driver=");
>> -        else if (!file && STRPREFIX(tmp, "file="))
>> -            file = tmp + strlen("file=");
>> +
>> +    name = array[0];
>> +    for (i = 1; i < narray; i++) {
>> +        if (!snapshot && STRPREFIX(array[i], "snapshot="))
>> +            snapshot = array[i] + strlen("snapshot=");
>> +        else if (!driver && STRPREFIX(array[i], "driver="))
>> +            driver = array[i] + strlen("driver=");
>> +        else if (!file && STRPREFIX(array[i], "file="))
>> +            file = array[i] + strlen("file=");
>>           else
>>               goto cleanup;
>>       }
>> @@ -245,7 +238,10 @@ vshParseSnapshotDiskspec(vshControl *ctl, virBufferPtr buf, const char *str)
>>   cleanup:
>>       if (ret < 0)
>>           vshError(ctl, _("unable to parse diskspec: %s"), str);
>> -    VIR_FREE(spec);
>> +    if (array) {
>> +        VIR_FREE(*array);
>> +        VIR_FREE(array);
>> +    }
>>       return ret;
>>   }
>>
>> diff --git a/tools/virsh.c b/tools/virsh.c
>> index a5585e1..9598b75 100644
>> --- a/tools/virsh.c
>> +++ b/tools/virsh.c
>> @@ -179,35 +179,46 @@ vshStringToArray(const char *str,
>>   {
>>       char *str_copied = vshStrdup(NULL, str);
>>       char *str_tok = NULL;
>> +    char *tmp;
>>       unsigned int nstr_tokens = 0;
>>       char **arr = NULL;
>> +    size_t len = strlen(str_copied);
>
> If str_copied is NULL due to an OOM (I think that's what vshStrdup
> does on OOM) or if someone was bad with their call to
> vshStringToArray() we'll go boom on this strlen().

vshStrdup calls exit() if it hits OOM so this part is OK.

>
>>
>>       /* tokenize the string from user and save it's parts into an array */
>> -    if (str_copied) {

As is taking this out of this condition.

>> -        nstr_tokens = 1;
>> -
>> -        /* count the delimiters */
>> -        str_tok = str_copied;
>> -        while (*str_tok) {
>> -            if (*str_tok == ',')
>> -                nstr_tokens++;
>> +    nstr_tokens = 1;
>> +
>> +    /* count the delimiters, recognizing ,, as an escape for a
>> +     * literal comma */
>> +    str_tok = str_copied;
>> +    while ((str_tok = strchr(str_tok, ','))) {
>> +        if (str_tok[1] == ',')
>>               str_tok++;
>> -        }
>> +        else
>> +            nstr_tokens++;
>> +        str_tok++;
>> +    }
>>
>> -        if (VIR_ALLOC_N(arr, nstr_tokens) < 0) {
>> -            virReportOOMError();
>> -            VIR_FREE(str_copied);
>> -            return -1;
>> -        }
>> +    if (VIR_ALLOC_N(arr, nstr_tokens) < 0) {
>> +        virReportOOMError();
>> +        VIR_FREE(str_copied);
>> +        return -1;
>> +    }
>>
>> -        /* tokenize the input string */
>> -        nstr_tokens = 0;
>> -        str_tok = str_copied;
>> -        do {
>> -            arr[nstr_tokens] = strsep(&str_tok, ",");
>> -            nstr_tokens++;
>> -        } while (str_tok);
>> +    /* tokenize the input string */
>> +    nstr_tokens = 0;
>> +    tmp = str_tok = str_copied;
>> +    while ((tmp = strchr(tmp, ','))) {
>> +        if (tmp[1] == ',') {
>> +            memmove(&tmp[1], &tmp[2], len - (tmp - str_copied) - 2 + 1);
>> +            len--;
>> +            tmp++;
>
> Not a review but just trying to understand it (maybe a short comment
> above for others like me that needed to pause to look at this would be
> nice) but basically you're just shifting off one of the double commas
> right? The code above looks correct for that.

I agree a line explaining what that part does would be nice, but not 
necessary.

>
>> +            continue;
>> +        }
>> +        *tmp++ = '\0';
>> +        arr[nstr_tokens++] = str_tok;
>> +        str_tok = tmp;
>>       }
>> +    arr[nstr_tokens++] = str_tok;
>>
>>       *array = arr;
>>       return nstr_tokens;
>> --
>> 1.7.11.7
>
> Just 1 little nit for the strlen(), which its possible we guarantee we
> won't hit that. And then a clarification. But otherwise this looks
> good so visual ACK. I haven't pulled it down and compiled it or syntax
> checked it.
>

ACK with or without the comment added.

Peter




More information about the libvir-list mailing list