Blob Blame History Raw
/*
 *   BSD LICENSE
 *
 *   Copyright(c) 2016 Intel Corporation. All rights reserved.
 *   All rights reserved.
 *
 *   Redistribution and use in source and binary forms, with or without
 *   modification, are permitted provided that the following conditions
 *   are met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in
 *       the documentation and/or other materials provided with the
 *       distribution.
 *     * Neither the name of Intel Corporation nor the names of its
 *       contributors may be used to endorse or promote products derived
 *       from this software without specific prior written permission.
 *
 *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#include "common.h"
#include "rdt.h"

int
str_to_cpuset(const char *cpustr, const unsigned cpustr_len, cpu_set_t *cpuset)
{
	unsigned idx, min, max;
	char *buff = malloc(cpustr_len + 1);
	char *end = NULL;
	const char *str = buff;
	int ret = 0;

	if (NULL == buff || NULL == cpustr || NULL == cpuset || 0 == cpustr_len)
		goto err;

	memcpy(buff, cpustr, cpustr_len);
	buff[cpustr_len] = 0;
	CPU_ZERO(cpuset);

	while (isblank(*str))
		str++;

	/* only digit is qualify for start point */
	if (!isdigit(*str) || *str == '\0')
		goto err;

	min = CPU_SETSIZE;
	do {
		/* go ahead to the first digit */
		while (isblank(*str))
			str++;

		if (!isdigit(*str))
			goto err;

		/* get the digit value */
		errno = 0;
		idx = strtoul(str, &end, 10);
		if (errno != 0 || end == NULL || end == str ||
				idx >= CPU_SETSIZE)
			goto err;

		/* go ahead to separator '-',',' */
		while (isblank(*end))
			end++;

		if (*end == '-') {
			if (min == CPU_SETSIZE)
				min = idx;
			else /* avoid continuous '-' */
				goto err;
		} else if (*end == ',' || *end == 0) {
			max = idx;

			if (min == CPU_SETSIZE)
				min = idx;

			for (idx = MIN(min, max); idx <= MAX(min, max);
					idx++)
				CPU_SET(idx, cpuset);

			min = CPU_SETSIZE;
		} else
			goto err;

		str = end + 1;
	} while (*end != '\0');

	ret = end - buff;

	free(buff);
	return ret;

err:
	if (buff != NULL)
		free(buff);
	return -EINVAL;
}

void
cpuset_to_str(char *cpustr, const unsigned cpustr_len,
		const cpu_set_t *cpuset)
{
	unsigned len = 0, j = 0;

	memset(cpustr, 0, cpustr_len);

	/* Generate CPU list */
	for (j = 0; j < CPU_SETSIZE; j++) {
		if (CPU_ISSET(j, cpuset) != 1)
			continue;

		len += snprintf(cpustr + len, cpustr_len - len - 1, "%u,", j);

		if (len >= cpustr_len - 1) {
			len = cpustr_len;
			memcpy(cpustr + cpustr_len - 4, "...", 3);
			break;
		}
	}

	/* Remove trailing separator */
	cpustr[len-1] = 0;
}

/**
 * @brief Function to check if a value is already contained in a table
 *
 * @param tab table of values to check
 * @param size size of the table
 * @param val value to search for
 *
 * @return If the value is already in the table
 * @retval 1 if value if found
 * @retval 0 if value is not found
 */
static int
isdup(const uint64_t *tab, const unsigned size, const uint64_t val)
{
        unsigned i;

        for (i = 0; i < size; i++)
                if (tab[i] == val)
                        return 1;
        return 0;
}

/**
 * @brief Converts string into 64-bit unsigned number.
 *
 * Numbers can be in decimal or hexadecimal format.
 * On error, this functions causes process to exit with FAILURE code.
 *
 * @param s string to be converted into 64-bit unsigned number
 *
 * @return Numeric value of the string representing the number
 */
static uint64_t
strtouint64(const char *s)
{
        const char *str = s;
        int base = 10;
        uint64_t n = 0;
        char *endptr = NULL;

        if (s == NULL)
                exit(EXIT_FAILURE);

        if (strncasecmp(s, "0x", 2) == 0) {
                base = 16;
                s += 2;
        }

        n = strtoull(s, &endptr, base);

        if (!(*s != '\0' && *endptr == '\0')) {
                printf("Error converting '%s' to unsigned number!\n", str);
                exit(EXIT_FAILURE);
        }

        return n;
}

unsigned
strlisttotab(char *s, uint64_t *tab, const unsigned max)
{
        unsigned index = 0;
        char *saveptr = NULL;

        if (s == NULL || tab == NULL || max == 0)
                return index;

        for (;;) {
                char *p = NULL;
                char *token = NULL;

                token = strtok_r(s, ",", &saveptr);
                if (token == NULL)
                        break;

                s = NULL;

                /* get rid of leading spaces & skip empty tokens */
                while (isspace(*token))
                        token++;
                if (*token == '\0')
                        continue;

                p = strchr(token, '-');
                if (p != NULL) {
                        /**
                         * range of numbers provided
                         * example: 1-5 or 12-9
                         */
                        uint64_t n, start, end;
                        *p = '\0';
                        start = strtouint64(token);
                        end = strtouint64(p+1);
                        if (start > end) {
                                /**
                                 * no big deal just swap start with end
                                 */
                                n = start;
                                start = end;
                                end = n;
                        }
                        for (n = start; n <= end; n++) {
                                if (!(isdup(tab, index, n))) {
                                        tab[index] = n;
                                        index++;
                                }
                                if (index >= max)
                                        return index;
                        }
                } else {
                        /**
                         * single number provided here
                         * remove duplicates if necessary
                         */
                        uint64_t val = strtouint64(token);

                        if (!(isdup(tab, index, val))) {
                                tab[index] = val;
                                index++;
                        }
                        if (index >= max)
                                return index;
                }
        }

        return index;
}