Example #1
0
static int
virQEMUDriverConfigNVRAMParse(const char *str,
                              char **loader,
                              char **nvram)
{
    int ret = -1;
    char **token;

    if (!(token = virStringSplit(str, ":", 0)))
        goto cleanup;

    if (token[0]) {
        virSkipSpaces((const char **) &token[0]);
        if (token[1])
            virSkipSpaces((const char **) &token[1]);
    }

    /* Exactly two tokens are expected */
    if (!token[0] || !token[1] || token[2] ||
        STREQ(token[0], "") || STREQ(token[1], "")) {
        virReportError(VIR_ERR_CONF_SYNTAX,
                       _("Invalid nvram format: '%s'"),
                       str);
        goto cleanup;
    }

    if (VIR_STRDUP(*loader, token[0]) < 0 ||
        VIR_STRDUP(*nvram, token[1]) < 0)
        goto cleanup;

    ret = 0;
 cleanup:
    virStringFreeList(token);
    return ret;
}
Example #2
0
static int
virSysinfoParseSystem(const char *base, virSysinfoDefPtr ret)
{
    char *eol = NULL;
    const char *cur;

    if ((cur = strstr(base, "platform")) == NULL)
        return 0;

    base = cur;
    /* Account for format 'platform    : XXXX'*/
    cur = strchr(cur, ':') + 1;
    eol = strchr(cur, '\n');
    virSkipSpaces(&cur);
    if (eol && VIR_STRNDUP(ret->system_family, cur, eol - cur) < 0)
        return -1;

    if ((cur = strstr(base, "model")) != NULL) {
        cur = strchr(cur, ':') + 1;
        eol = strchr(cur, '\n');
        virSkipSpaces(&cur);
        if (eol && VIR_STRNDUP(ret->system_serial, cur, eol - cur) < 0)
            return -1;
    }

    if ((cur = strstr(base, "machine")) != NULL) {
        cur = strchr(cur, ':') + 1;
        eol = strchr(cur, '\n');
        virSkipSpaces(&cur);
        if (eol && VIR_STRNDUP(ret->system_version, cur, eol - cur) < 0)
            return -1;
    }

    return 0;
}
Example #3
0
static int
virSysinfoParseSystem(const char *base, virSysinfoSystemDefPtr *sysdef)
{
    int ret = -1;
    char *eol = NULL;
    const char *cur;
    virSysinfoSystemDefPtr def;

    if ((cur = strstr(base, "platform")) == NULL)
        return 0;

    if (VIR_ALLOC(def) < 0)
        return ret;

    base = cur;
    /* Account for format 'platform    : XXXX'*/
    cur = strchr(cur, ':') + 1;
    eol = strchr(cur, '\n');
    virSkipSpaces(&cur);
    if (eol && VIR_STRNDUP(def->family, cur, eol - cur) < 0)
        goto cleanup;

    if ((cur = strstr(base, "model")) != NULL) {
        cur = strchr(cur, ':') + 1;
        eol = strchr(cur, '\n');
        virSkipSpaces(&cur);
        if (eol && VIR_STRNDUP(def->serial, cur, eol - cur) < 0)
            goto cleanup;
    }

    if ((cur = strstr(base, "machine")) != NULL) {
        cur = strchr(cur, ':') + 1;
        eol = strchr(cur, '\n');
        virSkipSpaces(&cur);
        if (eol && VIR_STRNDUP(def->version, cur, eol - cur) < 0)
            goto cleanup;
    }

    if (!def->manufacturer && !def->product && !def->version &&
        !def->serial && !def->uuid && !def->sku && !def->family) {
        virSysinfoSystemDefFree(def);
        def = NULL;
    }

    *sysdef = def;
    def = NULL;
    ret = 0;
 cleanup:
    virSysinfoSystemDefFree(def);
    return ret;
}
Example #4
0
static int
virSysinfoParseProcessor(const char *base, virSysinfoDefPtr ret)
{
    const char *cur;
    char *eol, *tmp_base;
    virSysinfoProcessorDefPtr processor;
    char *processor_type = NULL;

    if (!(tmp_base = strstr(base, "Processor")))
        return 0;

    base = tmp_base;
    eol = strchr(base, '\n');
    cur = strchr(base, ':') + 1;
    virSkipSpaces(&cur);
    if (eol &&
        ((processor_type = strndup(cur, eol - cur))
         == NULL))
        goto no_memory;
    base = cur;

    while ((tmp_base = strstr(base, "processor")) != NULL) {
        base = tmp_base;
        eol = strchr(base, '\n');
        cur = strchr(base, ':') + 1;

        if (VIR_EXPAND_N(ret->processor, ret->nprocessor, 1) < 0) {
            goto no_memory;
        }
        processor = &ret->processor[ret->nprocessor - 1];

        virSkipSpaces(&cur);
        if (eol &&
            ((processor->processor_socket_destination = strndup
                                     (cur, eol - cur)) == NULL))
            goto no_memory;

        if (processor_type &&
            !(processor->processor_type = strdup(processor_type)))
            goto no_memory;

        base = cur;
    }

    VIR_FREE(processor_type);
    return 0;

no_memory:
    VIR_FREE(processor_type);
    return -1;
}
Example #5
0
static int
virSysinfoParseProcessor(const char *base, virSysinfoDefPtr ret)
{
    const char *cur;
    char *eol, *tmp_base;
    virSysinfoProcessorDefPtr processor;
    char *processor_type = NULL;

    if (!(tmp_base = strstr(base, "Processor")))
        return 0;

    base = tmp_base;
    eol = strchr(base, '\n');
    cur = strchr(base, ':') + 1;
    virSkipSpaces(&cur);
    if (eol && VIR_STRNDUP(processor_type, cur, eol - cur) < 0)
        goto error;
    base = cur;

    while ((tmp_base = strstr(base, "processor")) != NULL) {
        base = tmp_base;
        eol = strchr(base, '\n');
        cur = strchr(base, ':') + 1;

        if (VIR_EXPAND_N(ret->processor, ret->nprocessor, 1) < 0)
            goto error;
        processor = &ret->processor[ret->nprocessor - 1];

        virSkipSpaces(&cur);
        if (eol &&
            VIR_STRNDUP(processor->processor_socket_destination,
                        cur, eol - cur) < 0)
            goto error;

        if (processor_type &&
            VIR_STRDUP(processor->processor_type, processor_type) < 0)
            goto error;

        base = cur;
    }

    VIR_FREE(processor_type);
    return 0;

error:
    VIR_FREE(processor_type);
    return -1;
}
Example #6
0
static bool
cmdVolResize(vshControl *ctl, const vshCmd *cmd)
{
    virStorageVolPtr vol;
    const char *capacityStr = NULL;
    unsigned long long capacity = 0;
    unsigned int flags = 0;
    bool ret = false;
    bool delta = false;

    if (vshCommandOptBool(cmd, "allocate"))
        flags |= VIR_STORAGE_VOL_RESIZE_ALLOCATE;
    if (vshCommandOptBool(cmd, "delta")) {
        delta = true;
        flags |= VIR_STORAGE_VOL_RESIZE_DELTA;
    }
    if (vshCommandOptBool(cmd, "shrink"))
        flags |= VIR_STORAGE_VOL_RESIZE_SHRINK;

    if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", NULL)))
        return false;

    if (vshCommandOptStringReq(ctl, cmd, "capacity", &capacityStr) < 0)
        goto cleanup;
    virSkipSpaces(&capacityStr);
    if (*capacityStr == '-') {
        /* The API always requires a positive value; but we allow a
         * negative value for convenience.  */
        if (delta && vshCommandOptBool(cmd, "shrink")){
            capacityStr++;
        } else {
            vshError(ctl, "%s",
                     _("negative size requires --delta and --shrink"));
            goto cleanup;
        }
    }
    if (vshVolSize(capacityStr, &capacity) < 0) {
        vshError(ctl, _("Malformed size %s"), capacityStr);
        goto cleanup;
    }

    if (virStorageVolResize(vol, capacity, flags) == 0) {
        vshPrint(ctl,
                 delta ? _("Size of volume '%s' successfully changed by %s\n")
                 : _("Size of volume '%s' successfully changed to %s\n"),
                 virStorageVolGetName(vol), capacityStr);
        ret = true;
    } else {
        vshError(ctl,
                 delta ? _("Failed to change size of volume '%s' by %s\n")
                 : _("Failed to change size of volume '%s' to %s\n"),
                 virStorageVolGetName(vol), capacityStr);
        ret = false;
    }

 cleanup:
    virStorageVolFree(vol);
    return ret;
}
Example #7
0
static int
virSysinfoParseProcessor(const char *base, virSysinfoDefPtr ret)
{
    const char *cur;
    char *eol, *tmp_base;
    virSysinfoProcessorDefPtr processor;

    while ((tmp_base = strstr(base, "processor")) != NULL) {
        base = tmp_base;
        eol = strchr(base, '\n');
        cur = strchr(base, ':') + 1;

        if (VIR_EXPAND_N(ret->processor, ret->nprocessor, 1) < 0) {
            return -1;
        }
        processor = &ret->processor[ret->nprocessor - 1];

        virSkipSpaces(&cur);
        if (eol && VIR_STRNDUP(processor->processor_socket_destination,
                               cur, eol - cur) < 0)
            return -1;

        if ((cur = strstr(base, "cpu")) != NULL) {
            cur = strchr(cur, ':') + 1;
            eol = strchr(cur, '\n');
            virSkipSpaces(&cur);
            if (eol && VIR_STRNDUP(processor->processor_type,
                                   cur, eol - cur) < 0)
                return -1;
        }

        if ((cur = strstr(base, "revision")) != NULL) {
            cur = strchr(cur, ':') + 1;
            eol = strchr(cur, '\n');
            virSkipSpaces(&cur);
            if (eol && VIR_STRNDUP(processor->processor_version,
                                   cur, eol - cur) < 0)
                return -1;
        }

        base = cur;
    }

    return 0;
}
Example #8
0
/**
 * virStringIsEmpty:
 * @str: string to check
 *
 * Returns true if string is empty (may contain only whitespace) or NULL.
 */
bool
virStringIsEmpty(const char *str)
{
    if (!str)
        return true;

    virSkipSpaces(&str);
    return str[0] == '\0';
}
Example #9
0
static int
virSysinfoParseSystem(const char *base, virSysinfoDefPtr ret)
{
    char *cur, *eol = NULL;
    const char *property;

    /* Return if Manufacturer field is not found */
    if ((cur = strstr(base, "Manufacturer")) == NULL)
        return 0;

    base = cur;
    if ((cur = strstr(base, "Manufacturer")) != NULL) {
        cur = strchr(cur, ':') + 1;
        eol = strchr(cur, '\n');
        virSkipSpacesBackwards(cur, &eol);
        if ((eol) && ((property = strndup(cur, eol - cur)) == NULL))
            goto no_memory;
        virSkipSpaces(&property);
        ret->system_manufacturer = (char *) property;
    }
    if ((cur = strstr(base, "Type")) != NULL) {
        cur = strchr(cur, ':') + 1;
        eol = strchr(cur, '\n');
        virSkipSpacesBackwards(cur, &eol);
        if ((eol) && ((property = strndup(cur, eol - cur)) == NULL))
            goto no_memory;
        virSkipSpaces(&property);
        ret->system_family = (char *) property;
    }
    if ((cur = strstr(base, "Sequence Code")) != NULL) {
        cur = strchr(cur, ':') + 1;
        eol = strchr(cur, '\n');
        virSkipSpacesBackwards(cur, &eol);
        if ((eol) && ((property = strndup(cur, eol - cur)) == NULL))
            goto no_memory;
        virSkipSpaces(&property);
        ret->system_serial = (char *) property;
    }

    return 0;

no_memory:
    return -1;
}
Example #10
0
static int
virSysinfoParseSystem(const char *base, virSysinfoDefPtr ret)
{
    char *eol = NULL;
    const char *cur;

    if ((cur = strstr(base, "platform")) == NULL)
        return 0;

    base = cur;
    /* Account for format 'platform    : XXXX'*/
    cur = strchr(cur, ':') + 1;
    eol = strchr(cur, '\n');
    virSkipSpaces(&cur);
    if (eol &&
       ((ret->system_family = strndup(cur, eol - cur)) == NULL))
         goto no_memory;

    if ((cur = strstr(base, "model")) != NULL) {
        cur = strchr(cur, ':') + 1;
        eol = strchr(cur, '\n');
        virSkipSpaces(&cur);
        if (eol && ((ret->system_serial = strndup(cur, eol - cur))
                                                           == NULL))
            goto no_memory;
    }

    if ((cur = strstr(base, "machine")) != NULL) {
        cur = strchr(cur, ':') + 1;
        eol = strchr(cur, '\n');
        virSkipSpaces(&cur);
        if (eol && ((ret->system_version = strndup(cur, eol - cur))
                                                            == NULL))
            goto no_memory;
    }

    return 0;

no_memory:
    return -1;
}
Example #11
0
static int
dnsmasqCapsSetFromBuffer(dnsmasqCapsPtr caps, const char *buf)
{
    const char *p;

    caps->noRefresh = true;

    p = STRSKIP(buf, DNSMASQ_VERSION_STR);
    if (!p)
       goto fail;
    virSkipSpaces(&p);
    if (virParseVersionString(p, &caps->version, true) < 0)
        goto fail;

    if (strstr(buf, "--bind-dynamic"))
        dnsmasqCapsSet(caps, DNSMASQ_CAPS_BIND_DYNAMIC);

    /* if this string is a part of the --version output, dnsmasq
     * has been patched to use SO_BINDTODEVICE when listening,
     * so that it will only accept requests that arrived on the
     * listening interface(s)
     */
    if (strstr(buf, "--bind-interfaces with SO_BINDTODEVICE"))
        dnsmasqCapsSet(caps, DNSMASQ_CAPS_BINDTODEVICE);

    if (strstr(buf, "--ra-param"))
        dnsmasqCapsSet(caps, DNSMASQ_CAPS_RA_PARAM);

    VIR_INFO("dnsmasq version is %d.%d, --bind-dynamic is %spresent, "
             "SO_BINDTODEVICE is %sin use, --ra-param is %spresent",
             (int)caps->version / 1000000,
             (int)(caps->version % 1000000) / 1000,
             dnsmasqCapsGet(caps, DNSMASQ_CAPS_BIND_DYNAMIC) ? "" : "NOT ",
             dnsmasqCapsGet(caps, DNSMASQ_CAPS_BINDTODEVICE) ? "" : "NOT ",
             dnsmasqCapsGet(caps, DNSMASQ_CAPS_RA_PARAM) ? "" : "NOT ");
    return 0;

 fail:
    p = strchrnul(buf, '\n');
    virReportError(VIR_ERR_INTERNAL_ERROR,
                   _("cannot parse %s version number in '%.*s'"),
                   caps->binaryPath, (int) (p - buf), buf);
    return -1;

}
Example #12
0
static char *
virSysinfoParseDelimited(const char *base, const char *name, char **value,
                         char delim1, char delim2)
{
    const char *start;
    char *end;

    if (delim1 != delim2 &&
        (start = strstr(base, name)) &&
        (start = strchr(start, delim1))) {
        start += 1;
        end = strchrnul(start, delim2);
        virSkipSpaces(&start);
        if (VIR_STRNDUP(*value, start, end - start) < 0)
            return NULL;
        virTrimSpaces(*value, NULL);
        return end;
    }
    return NULL;
}
Example #13
0
static char *
virSysinfoParseDelimited(const char *base, const char *name, char **value,
                         char delim1, char delim2)
{
    const char *start;
    char *end;

    if (delim1 != delim2 &&
        (start = strstr(base, name)) &&
        (start = strchr(start, delim1))) {
        start += 1;
        end = strchrnul(start, delim2);
        virSkipSpaces(&start);
        if (!((*value) = strndup(start, end - start))) {
            virReportOOMError();
            goto error;
        }
        virTrimSpaces(*value, NULL);
        return end;
    }

error:
    return NULL;
}
Example #14
0
static int
virSysinfoParseProcessor(const char *base, virSysinfoDefPtr ret)
{
    char *cur, *eol, *tmp_base;
    char *manufacturer;
    const char *tmp;
    virSysinfoProcessorDefPtr processor;

    if ((cur = strstr(base, "vendor_id")) != NULL) {
        cur = strchr(cur, ':') + 1;
        eol = strchr(cur, '\n');
        virSkipSpacesBackwards(cur, &eol);
        if ((eol) && ((tmp = strndup(cur, eol - cur)) == NULL))
            goto no_memory;
        virSkipSpaces(&tmp);
        manufacturer = (char *) tmp;
    }

    /* Find processor N: line and gather the processor manufacturer, version,
     * serial number, and family */
    while ((tmp_base = strstr(base, "processor ")) != NULL) {
        base = tmp_base;
        eol = strchr(base, '\n');
        cur = strchr(base, ':') + 1;

        if (VIR_EXPAND_N(ret->processor, ret->nprocessor, 1) < 0) {
            goto no_memory;
        }

        processor = &ret->processor[ret->nprocessor - 1];

        /* Set the processor manufacturer */
        processor->processor_manufacturer = manufacturer;

        if ((cur = strstr(base, "version =")) != NULL) {
            cur += sizeof("version =");
            eol = strchr(cur, ',');
            if ((eol) &&
                ((processor->processor_version = strndup(cur, eol - cur)) == NULL))
                goto no_memory;
        }
        if ((cur = strstr(base, "identification =")) != NULL) {
            cur += sizeof("identification =");
            eol = strchr(cur, ',');
            if ((eol) &&
                ((processor->processor_serial_number = strndup(cur, eol - cur)) == NULL))
                goto no_memory;
        }
        if ((cur = strstr(base, "machine =")) != NULL) {
            cur += sizeof("machine =");
            eol = strchr(cur, '\n');
            if ((eol) &&
                ((processor->processor_family = strndup(cur, eol - cur)) == NULL))
                goto no_memory;
        }

        base = cur;
    }

    return 0;

no_memory:
    return -1;
}
Example #15
0
/**
 * virBitmapParse:
 * @str: points to a string representing a human-readable bitmap
 * @terminator: character separating the bitmap to parse
 * @bitmap: a bitmap created from @str
 * @bitmapSize: the upper limit of num of bits in created bitmap
 *
 * This function is the counterpart of virBitmapFormat. This function creates
 * a bitmap, in which bits are set according to the content of @str.
 *
 * @str is a comma separated string of fields N, which means a number of bit
 * to set, and ^N, which means to unset the bit, and N-M for ranges of bits
 * to set.
 *
 * To allow parsing of bitmaps within larger strings it is possible to set
 * a termination character in the argument @terminator. When the character
 * in @terminator is encountered in @str, the parsing of the bitmap stops.
 * Pass 0 as @terminator if it is not needed. Whitespace characters may not
 * be used as terminators.
 *
 * Returns the number of bits set in @bitmap, or -1 in case of error.
 */
int
virBitmapParse(const char *str,
               char terminator,
               virBitmapPtr *bitmap,
               size_t bitmapSize)
{
    bool neg = false;
    const char *cur = str;
    char *tmp;
    size_t i;
    int start, last;

    if (!(*bitmap = virBitmapNew(bitmapSize)))
        return -1;

    if (!str)
        goto error;

    virSkipSpaces(&cur);

    if (*cur == '\0')
        goto error;

    while (*cur != 0 && *cur != terminator) {
        /*
         * 3 constructs are allowed:
         *     - N   : a single CPU number
         *     - N-M : a range of CPU numbers with N < M
         *     - ^N  : remove a single CPU number from the current set
         */
        if (*cur == '^') {
            cur++;
            neg = true;
        }

        if (!c_isdigit(*cur))
            goto error;

        if (virStrToLong_i(cur, &tmp, 10, &start) < 0)
            goto error;
        if (start < 0)
            goto error;

        cur = tmp;

        virSkipSpaces(&cur);

        if (*cur == ',' || *cur == 0 || *cur == terminator) {
            if (neg) {
                if (virBitmapClearBit(*bitmap, start) < 0)
                    goto error;
            } else {
                if (virBitmapSetBit(*bitmap, start) < 0)
                    goto error;
            }
        } else if (*cur == '-') {
            if (neg)
                goto error;

            cur++;
            virSkipSpaces(&cur);

            if (virStrToLong_i(cur, &tmp, 10, &last) < 0)
                goto error;
            if (last < start)
                goto error;

            cur = tmp;

            for (i = start; i <= last; i++) {
                if (virBitmapSetBit(*bitmap, i) < 0)
                    goto error;
            }

            virSkipSpaces(&cur);
        }

        if (*cur == ',') {
            cur++;
            virSkipSpaces(&cur);
            neg = false;
        } else if (*cur == 0 || *cur == terminator) {
            break;
        } else {
            goto error;
        }
    }

    if (virBitmapIsAllClear(*bitmap))
        goto error;

    return virBitmapCountBits(*bitmap);

 error:
    virReportError(VIR_ERR_INVALID_ARG,
                   _("Failed to parse bitmap '%s'"), str);
    virBitmapFree(*bitmap);
    *bitmap = NULL;
    return -1;
}
Example #16
0
int virBitmapParse(const char *str,
                   char sep,
                   virBitmapPtr *bitmap,
                   size_t bitmapSize)
{
    int ret = 0;
    bool neg = false;
    const char *cur;
    char *tmp;
    int i, start, last;

    if (!str)
        return -1;

    cur = str;
    virSkipSpaces(&cur);

    if (*cur == 0)
        return -1;

    *bitmap = virBitmapNew(bitmapSize);
    if (!*bitmap)
        return -1;

    while (*cur != 0 && *cur != sep) {
        /*
         * 3 constructs are allowed:
         *     - N   : a single CPU number
         *     - N-M : a range of CPU numbers with N < M
         *     - ^N  : remove a single CPU number from the current set
         */
        if (*cur == '^') {
            cur++;
            neg = true;
        }

        if (!c_isdigit(*cur))
            goto parse_error;

        if (virStrToLong_i(cur, &tmp, 10, &start) < 0)
            goto parse_error;
        if (start < 0)
            goto parse_error;

        cur = tmp;

        virSkipSpaces(&cur);

        if (*cur == ',' || *cur == 0 || *cur == sep) {
            if (neg) {
                if (virBitmapIsSet(*bitmap, start)) {
                    ignore_value(virBitmapClearBit(*bitmap, start));
                    ret--;
                }
            } else {
                if (!virBitmapIsSet(*bitmap, start)) {
                    ignore_value(virBitmapSetBit(*bitmap, start));
                    ret++;
                }
            }
        } else if (*cur == '-') {
            if (neg)
                goto parse_error;

            cur++;
            virSkipSpaces(&cur);

            if (virStrToLong_i(cur, &tmp, 10, &last) < 0)
                goto parse_error;
            if (last < start)
                goto parse_error;

            cur = tmp;

            for (i = start; i <= last; i++) {
                if (!virBitmapIsSet(*bitmap, i)) {
                    ignore_value(virBitmapSetBit(*bitmap, i));
                    ret++;
                }
            }

            virSkipSpaces(&cur);
        }

        if (*cur == ',') {
            cur++;
            virSkipSpaces(&cur);
            neg = false;
        } else if(*cur == 0 || *cur == sep) {
            break;
        } else {
            goto parse_error;
        }
    }

    return ret;

parse_error:
    virBitmapFree(*bitmap);
    *bitmap = NULL;
    return -1;
}
Example #17
0
/**
 * virBitmapParseUnlimited:
 * @str: points to a string representing a human-readable bitmap
 *
 * This function is the counterpart of virBitmapFormat. This function creates
 * a bitmap, in which bits are set according to the content of @str.
 *
 * The bitmap is expanded to accomodate all the bits.
 *
 * @str is a comma separated string of fields N, which means a number of bit
 * to set, and ^N, which means to unset the bit, and N-M for ranges of bits
 * to set.
 *
 * Returns @bitmap on success, or NULL in case of error
 */
virBitmapPtr
virBitmapParseUnlimited(const char *str)
{
    virBitmapPtr bitmap;
    bool neg = false;
    const char *cur = str;
    char *tmp;
    size_t i;
    int start, last;

    if (!(bitmap = virBitmapNewEmpty()))
        return NULL;

    if (!str)
        goto error;

    virSkipSpaces(&cur);

    if (*cur == '\0')
        goto error;

    while (*cur != 0) {
        /*
         * 3 constructs are allowed:
         *     - N   : a single CPU number
         *     - N-M : a range of CPU numbers with N < M
         *     - ^N  : remove a single CPU number from the current set
         */
        if (*cur == '^') {
            cur++;
            neg = true;
        }

        if (!c_isdigit(*cur))
            goto error;

        if (virStrToLong_i(cur, &tmp, 10, &start) < 0)
            goto error;
        if (start < 0)
            goto error;

        cur = tmp;

        virSkipSpaces(&cur);

        if (*cur == ',' || *cur == 0) {
            if (neg) {
                if (virBitmapClearBitExpand(bitmap, start) < 0)
                    goto error;
            } else {
                if (virBitmapSetBitExpand(bitmap, start) < 0)
                    goto error;
            }
        } else if (*cur == '-') {
            if (neg)
                goto error;

            cur++;
            virSkipSpaces(&cur);

            if (virStrToLong_i(cur, &tmp, 10, &last) < 0)
                goto error;
            if (last < start)
                goto error;

            cur = tmp;

            for (i = start; i <= last; i++) {
                if (virBitmapSetBitExpand(bitmap, i) < 0)
                    goto error;
            }

            virSkipSpaces(&cur);
        }

        if (*cur == ',') {
            cur++;
            virSkipSpaces(&cur);
            neg = false;
        } else if (*cur == 0) {
            break;
        } else {
            goto error;
        }
    }

    return bitmap;

 error:
    virReportError(VIR_ERR_INVALID_ARG,
                   _("Failed to parse bitmap '%s'"), NULLSTR(str));
    virBitmapFree(bitmap);
    return NULL;
}