Ejemplo n.º 1
0
/**
 * Return true if @p type is an array type, false otherwise.
 * 
 * @param type The type to query.
 */
bool
bhnd_nvram_is_array_type(bhnd_nvram_type type)
{
	switch (type) {
	case BHND_NVRAM_TYPE_UINT8:
	case BHND_NVRAM_TYPE_UINT16:
	case BHND_NVRAM_TYPE_UINT32:
	case BHND_NVRAM_TYPE_UINT64:
	case BHND_NVRAM_TYPE_INT8:
	case BHND_NVRAM_TYPE_INT16:
	case BHND_NVRAM_TYPE_INT32:
	case BHND_NVRAM_TYPE_INT64:
	case BHND_NVRAM_TYPE_CHAR:
	case BHND_NVRAM_TYPE_STRING:
		return (false);

	case BHND_NVRAM_TYPE_UINT8_ARRAY:
	case BHND_NVRAM_TYPE_UINT16_ARRAY:
	case BHND_NVRAM_TYPE_UINT32_ARRAY:
	case BHND_NVRAM_TYPE_UINT64_ARRAY:
	case BHND_NVRAM_TYPE_INT8_ARRAY:
	case BHND_NVRAM_TYPE_INT16_ARRAY:
	case BHND_NVRAM_TYPE_INT32_ARRAY:
	case BHND_NVRAM_TYPE_INT64_ARRAY:
	case BHND_NVRAM_TYPE_CHAR_ARRAY:
	case BHND_NVRAM_TYPE_STRING_ARRAY:
		return (true);
	}

	/* Quiesce gcc4.2 */
	BHND_NV_PANIC("bhnd nvram type %u unknown", type);
}
Ejemplo n.º 2
0
/**
 * If @p type is an array type, return the base element type. Otherwise,
 * returns @p type.
 * 
 * @param type The type to query.
 */
bhnd_nvram_type
bhnd_nvram_base_type(bhnd_nvram_type type)
{
	switch (type) {
	case BHND_NVRAM_TYPE_UINT8:
	case BHND_NVRAM_TYPE_UINT16:
	case BHND_NVRAM_TYPE_UINT32:
	case BHND_NVRAM_TYPE_UINT64:
	case BHND_NVRAM_TYPE_INT8:
	case BHND_NVRAM_TYPE_INT16:
	case BHND_NVRAM_TYPE_INT32:
	case BHND_NVRAM_TYPE_INT64:
	case BHND_NVRAM_TYPE_CHAR:
	case BHND_NVRAM_TYPE_STRING:
		return (type);

	case BHND_NVRAM_TYPE_UINT8_ARRAY:	return (BHND_NVRAM_TYPE_UINT8);
	case BHND_NVRAM_TYPE_UINT16_ARRAY:	return (BHND_NVRAM_TYPE_UINT16);
	case BHND_NVRAM_TYPE_UINT32_ARRAY:	return (BHND_NVRAM_TYPE_UINT32);
	case BHND_NVRAM_TYPE_UINT64_ARRAY:	return (BHND_NVRAM_TYPE_UINT64);
	case BHND_NVRAM_TYPE_INT8_ARRAY:	return (BHND_NVRAM_TYPE_INT8);
	case BHND_NVRAM_TYPE_INT16_ARRAY:	return (BHND_NVRAM_TYPE_INT16);
	case BHND_NVRAM_TYPE_INT32_ARRAY:	return (BHND_NVRAM_TYPE_INT32);
	case BHND_NVRAM_TYPE_INT64_ARRAY:	return (BHND_NVRAM_TYPE_INT64);
	case BHND_NVRAM_TYPE_CHAR_ARRAY:	return (BHND_NVRAM_TYPE_CHAR);
	case BHND_NVRAM_TYPE_STRING_ARRAY:	return (BHND_NVRAM_TYPE_STRING);
	}

	/* Quiesce gcc4.2 */
	BHND_NV_PANIC("bhnd nvram type %u unknown", type);
}
Ejemplo n.º 3
0
/**
 * Return true if @p type is a signed integer type, false otherwise.
 * 
 * Will return false for all array types.
 * 
 * @param type The type to query.
 */
bool
bhnd_nvram_is_signed_type(bhnd_nvram_type type)
{
	switch (type) {
	case BHND_NVRAM_TYPE_INT8:
	case BHND_NVRAM_TYPE_INT16:
	case BHND_NVRAM_TYPE_INT32:
	case BHND_NVRAM_TYPE_INT64:
		BHND_NV_ASSERT(bhnd_nvram_is_int_type(type), ("non-int type?"));
		return (true);

	case BHND_NVRAM_TYPE_CHAR:
	case BHND_NVRAM_TYPE_UINT8:
	case BHND_NVRAM_TYPE_UINT16:
	case BHND_NVRAM_TYPE_UINT32:
	case BHND_NVRAM_TYPE_UINT64:
	case BHND_NVRAM_TYPE_STRING:
	case BHND_NVRAM_TYPE_UINT8_ARRAY:
	case BHND_NVRAM_TYPE_UINT16_ARRAY:
	case BHND_NVRAM_TYPE_UINT32_ARRAY:
	case BHND_NVRAM_TYPE_UINT64_ARRAY:
	case BHND_NVRAM_TYPE_INT8_ARRAY:
	case BHND_NVRAM_TYPE_INT16_ARRAY:
	case BHND_NVRAM_TYPE_INT32_ARRAY:
	case BHND_NVRAM_TYPE_INT64_ARRAY:
	case BHND_NVRAM_TYPE_CHAR_ARRAY:
	case BHND_NVRAM_TYPE_STRING_ARRAY:
		return (false);
	}

	/* Quiesce gcc4.2 */
	BHND_NV_PANIC("bhnd nvram type %u unknown", type);
}
Ejemplo n.º 4
0
/**
 * Return a human readable name for @p type.
 * 
 * @param type The type to query.
 */
const char *
bhnd_nvram_type_name(bhnd_nvram_type type)
{
	switch (type) {
	case BHND_NVRAM_TYPE_UINT8:
		return ("uint8");
	case BHND_NVRAM_TYPE_UINT16:
		return ("uint16");
	case BHND_NVRAM_TYPE_UINT32:
		return ("uint32");
	case BHND_NVRAM_TYPE_UINT64:
		return ("uint64");
	case BHND_NVRAM_TYPE_CHAR:
		return ("char");
	case BHND_NVRAM_TYPE_INT8:
		return ("int8");
	case BHND_NVRAM_TYPE_INT16:
		return ("int16");
	case BHND_NVRAM_TYPE_INT32:
		return ("int32");
	case BHND_NVRAM_TYPE_INT64:
		return ("int64");
	case BHND_NVRAM_TYPE_STRING:
		return ("string");
	case BHND_NVRAM_TYPE_BOOL:
		return ("bool");
	case BHND_NVRAM_TYPE_NULL:
		return ("null");
	case BHND_NVRAM_TYPE_DATA:
		return ("data");
	case BHND_NVRAM_TYPE_UINT8_ARRAY:
		return ("uint8[]");
	case BHND_NVRAM_TYPE_UINT16_ARRAY:
		return ("uint16[]");
	case BHND_NVRAM_TYPE_UINT32_ARRAY:
		return ("uint32[]");
	case BHND_NVRAM_TYPE_UINT64_ARRAY:
		return ("uint64[]");
	case BHND_NVRAM_TYPE_INT8_ARRAY:
		return ("int8[]");
	case BHND_NVRAM_TYPE_INT16_ARRAY:
		return ("int16[]");
	case BHND_NVRAM_TYPE_INT32_ARRAY:
		return ("int32[]");
	case BHND_NVRAM_TYPE_INT64_ARRAY:
		return ("int64[]");
	case BHND_NVRAM_TYPE_CHAR_ARRAY:
		return ("char[]");
	case BHND_NVRAM_TYPE_STRING_ARRAY:
		return ("string[]");
	case BHND_NVRAM_TYPE_BOOL_ARRAY:
		return ("bool[]");
	}

	/* Quiesce gcc4.2 */
	BHND_NV_PANIC("bhnd nvram type %u unknown", type);
}
Ejemplo n.º 5
0
/**
 * Return the raw data type used to represent values of @p type, or return
 * @p type is @p type is not a complex type.
 *
 * @param type The type to query.
 */
bhnd_nvram_type
bhnd_nvram_raw_type(bhnd_nvram_type type)
{
	switch (type) {
	case BHND_NVRAM_TYPE_CHAR:
		return (BHND_NVRAM_TYPE_UINT8);

	case BHND_NVRAM_TYPE_CHAR_ARRAY:
		return (BHND_NVRAM_TYPE_UINT8_ARRAY);

	case BHND_NVRAM_TYPE_BOOL: {
		_Static_assert(sizeof(bhnd_nvram_bool_t) == sizeof(uint8_t),
		    "bhnd_nvram_bool_t must be uint8-representable");
		return (BHND_NVRAM_TYPE_UINT8);
	}

	case BHND_NVRAM_TYPE_BOOL_ARRAY:
		return (BHND_NVRAM_TYPE_UINT8_ARRAY);

	case BHND_NVRAM_TYPE_DATA:
		return (BHND_NVRAM_TYPE_UINT8_ARRAY);

	case BHND_NVRAM_TYPE_STRING:
	case BHND_NVRAM_TYPE_STRING_ARRAY:
		return (BHND_NVRAM_TYPE_UINT8_ARRAY);

	case BHND_NVRAM_TYPE_UINT8:
	case BHND_NVRAM_TYPE_UINT16:
	case BHND_NVRAM_TYPE_UINT32:
	case BHND_NVRAM_TYPE_UINT64:
	case BHND_NVRAM_TYPE_INT8:
	case BHND_NVRAM_TYPE_INT16:
	case BHND_NVRAM_TYPE_INT32:
	case BHND_NVRAM_TYPE_INT64:
	case BHND_NVRAM_TYPE_NULL:
	case BHND_NVRAM_TYPE_UINT8_ARRAY:
	case BHND_NVRAM_TYPE_UINT16_ARRAY:
	case BHND_NVRAM_TYPE_UINT32_ARRAY:
	case BHND_NVRAM_TYPE_UINT64_ARRAY:
	case BHND_NVRAM_TYPE_INT8_ARRAY:
	case BHND_NVRAM_TYPE_INT16_ARRAY:
	case BHND_NVRAM_TYPE_INT32_ARRAY:
	case BHND_NVRAM_TYPE_INT64_ARRAY:
		return (type);
	}

	/* Quiesce gcc4.2 */
	BHND_NV_PANIC("bhnd nvram type %u unknown", type);
}
Ejemplo n.º 6
0
/**
 * Return the size, in bytes, of a single element of @p type, or 0
 * if @p type is a variable-width type.
 * 
 * @param type	The type to query.
 */
size_t
bhnd_nvram_type_width(bhnd_nvram_type type)
{
	switch (type) {
	case BHND_NVRAM_TYPE_STRING:
	case BHND_NVRAM_TYPE_STRING_ARRAY:
	case BHND_NVRAM_TYPE_DATA:
		return (0);

	case BHND_NVRAM_TYPE_NULL:
		return (0);

	case BHND_NVRAM_TYPE_BOOL:
	case BHND_NVRAM_TYPE_BOOL_ARRAY:
		return (sizeof(bhnd_nvram_bool_t));

	case BHND_NVRAM_TYPE_CHAR:
	case BHND_NVRAM_TYPE_CHAR_ARRAY:
	case BHND_NVRAM_TYPE_UINT8:
	case BHND_NVRAM_TYPE_UINT8_ARRAY:
	case BHND_NVRAM_TYPE_INT8:
	case BHND_NVRAM_TYPE_INT8_ARRAY:
		return (sizeof(uint8_t));

	case BHND_NVRAM_TYPE_UINT16:
	case BHND_NVRAM_TYPE_UINT16_ARRAY:
	case BHND_NVRAM_TYPE_INT16:
	case BHND_NVRAM_TYPE_INT16_ARRAY:
		return (sizeof(uint16_t));

	case BHND_NVRAM_TYPE_UINT32:
	case BHND_NVRAM_TYPE_UINT32_ARRAY:
	case BHND_NVRAM_TYPE_INT32:
	case BHND_NVRAM_TYPE_INT32_ARRAY:
		return (sizeof(uint32_t));

	case BHND_NVRAM_TYPE_UINT64:
	case BHND_NVRAM_TYPE_UINT64_ARRAY:
	case BHND_NVRAM_TYPE_INT64:
	case BHND_NVRAM_TYPE_INT64_ARRAY:
		return (sizeof(uint64_t));
	}

	/* Quiesce gcc4.2 */
	BHND_NV_PANIC("bhnd nvram type %u unknown", type);
}
Ejemplo n.º 7
0
/**
 * Iterate over @p nv, returning the names of subsequent variables.
 * 
 * @param		nv	The NVRAM data to be iterated.
 * @param[in,out]	cookiep	A pointer to a cookiep value previously returned
 *				by bhnd_nvram_data_next(), or a NULL value to
 *				begin iteration.
 * 
 * @return Returns the next variable name, or NULL if there are no more
 * variables defined in @p nv.
 */
const char *
bhnd_nvram_data_next(struct bhnd_nvram_data *nv, void **cookiep)
{
	const char	*name;
#ifdef BHND_NV_INVARIANTS
	void		*prev = *cookiep;
#endif

	/* Fetch next */
	if ((name = nv->cls->op_next(nv, cookiep)) == NULL)
		return (NULL);

	/* Enforce precedence ordering invariant between bhnd_nvram_data_next()
	 * and bhnd_nvram_data_getvar_order() */
#ifdef BHND_NV_INVARIANTS
	if (prev != NULL &&
	    bhnd_nvram_data_getvar_order(nv, prev, *cookiep) > 0)
	{
		BHND_NV_PANIC("%s: returned out-of-order entry", __FUNCTION__);
	}
#endif

	return (name);
}
Ejemplo n.º 8
0
/**
 * Parses the string in the optionally NUL-terminated @p str to as an integer
 * value of @p otype, accepting any integer format supported by the standard
 * strtoul().
 * 
 * - Any leading whitespace in @p str -- as defined by the equivalent of
 *   calling isspace_l() with an ASCII locale -- will be ignored.
 * - A @p str may be prefixed with a single optional '+' or '-' sign denoting
 *   signedness.
 * - A hexadecimal @p str may include an '0x' or '0X' prefix, denoting that a
 *   base 16 integer follows.
 * - An octal @p str may include a '0' prefix, denoting that an octal integer
 *   follows.
 * 
 * If a @p base of 0 is specified, the base will be determined according
 * to the string's initial prefix, as per strtoul()'s documented behavior.
 *
 * When parsing a base 16 integer to a signed representation, if no explicit
 * sign prefix is given, the string will be parsed as the raw two's complement
 * representation of the signed integer value.
 *
 * @param		str	The string to be parsed.
 * @param		maxlen	The maximum number of bytes to be read in
 *				@p str.
 * @param		base	The input string's base (2-36), or 0.
 * @param[out]		nbytes	On success or failure, will be set to the total
 *				number of parsed bytes. If the total number of
 *				bytes is not desired, a NULL pointer may be
 *				provided.
 * @param[out]		outp	On success, the parsed integer value will be
 *				written to @p outp. This argment may be NULL if
 *				the value is not desired.
 * @param[in,out]	olen	The capacity of @p outp. On success, will be set
 *				to the actual size of the requested value.
 * @param		otype	The integer type to be parsed.
 *
 * @retval 0		success
 * @retval EINVAL	if an invalid @p base is specified.
 * @retval EINVAL	if an unsupported (or non-integer) @p otype is
 *			specified.
 * @retval ENOMEM	If @p outp is non-NULL and a buffer of @p olen is too
 *			small to hold the requested value.
 * @retval EFTYPE	if @p str cannot be parsed as an integer of @p base.
 * @retval ERANGE	If the integer parsed from @p str is too large to be
 *			represented as a value of @p otype.
 */
int
bhnd_nvram_parse_int(const char *str, size_t maxlen,  u_int base,
    size_t *nbytes, void *outp, size_t *olen, bhnd_nvram_type otype)
{
	uint64_t	value;
	uint64_t	carry_max, value_max;
	uint64_t	type_max;
	size_t		limit, local_nbytes;
	size_t		ndigits;
	bool		negative, sign, twos_compl;

	/* Must be an integer type */
	if (!bhnd_nvram_is_int_type(otype))
		return (EINVAL);

	/* Determine output byte limit */
	if (outp != NULL)
		limit = *olen;
	else
		limit = 0;

	/* We always need a byte count. If the caller provides a NULL nbytes,
	 * track our position in a stack variable */
	if (nbytes == NULL)
		nbytes = &local_nbytes;

	value = 0;
	ndigits = 0;
	*nbytes = 0;
	negative = false;
	sign = false;

	/* Validate the specified base */
	if (base != 0 && !(base >= 2 && base <= 36))
		return (EINVAL);

	/* Skip any leading whitespace */
	for (; *nbytes < maxlen; (*nbytes)++) {
		if (!bhnd_nv_isspace(str[*nbytes]))
			break;
	}

	/* Empty string? */
	if (*nbytes == maxlen)
		return (EFTYPE);

	/* Parse and skip sign */
	if (str[*nbytes] == '-') {
		negative = true;
		sign = true;
		(*nbytes)++;
	} else if (str[*nbytes] == '+') {
		sign = true;
		(*nbytes)++;
	}

	/* Truncated after sign character? */
	if (*nbytes == maxlen)
		return (EFTYPE);

	/* Identify (or validate) hex base, skipping 0x/0X prefix */
	if (base == 16 || base == 0) {
		/* Check for (and skip) 0x/0X prefix */
		if (maxlen - *nbytes >= 2 && str[*nbytes] == '0' &&
		    (str[*nbytes+1] == 'x' || str[*nbytes+1] == 'X'))
		{
			base = 16;
			(*nbytes) += 2;
		}
	}

	/* Truncated after hex prefix? */
	if (*nbytes == maxlen)
		return (EFTYPE);

	/* Differentiate decimal/octal by looking for a leading 0 */
	if (base == 0) {
		if (str[*nbytes] == '0') {
			base = 8;
		} else {
			base = 10;
		}
	}

	/* Only enable twos-compliment signed integer parsing enabled if the
	 * input is base 16, and no explicit sign prefix was provided */
	if (!sign && base == 16)
		twos_compl = true;
	else
		twos_compl = false;

	/* Determine the maximum value representable by the requested type */
	switch (otype) {
	case BHND_NVRAM_TYPE_CHAR:
	case BHND_NVRAM_TYPE_UINT8:
		type_max = (uint64_t)UINT8_MAX;
		break;
	case BHND_NVRAM_TYPE_UINT16:
		type_max = (uint64_t)UINT16_MAX;
		break;
	case BHND_NVRAM_TYPE_UINT32:
		type_max = (uint64_t)UINT32_MAX;
		break;
	case BHND_NVRAM_TYPE_UINT64:
		type_max = (uint64_t)UINT64_MAX;
		break;

	case BHND_NVRAM_TYPE_INT8:
		if (twos_compl)
			type_max = (uint64_t)UINT8_MAX;
		else if (negative)
			type_max = -(uint64_t)INT8_MIN;
		else
			type_max = (uint64_t)INT8_MAX;
		break;

	case BHND_NVRAM_TYPE_INT16:
		if (twos_compl)
			type_max = (uint64_t)UINT16_MAX;
		else if (negative)
			type_max = -(uint64_t)INT16_MIN;
		else
			type_max = (uint64_t)INT16_MAX;
		break;

	case BHND_NVRAM_TYPE_INT32:
		if (twos_compl)
			type_max = (uint64_t)UINT32_MAX;
		else if (negative)
			type_max = -(uint64_t)INT32_MIN;
		else
			type_max = (uint64_t)INT32_MAX;
		break;

	case BHND_NVRAM_TYPE_INT64:
		if (twos_compl)
			type_max = (uint64_t)UINT64_MAX;
		else if (negative)
			type_max = -(uint64_t)INT64_MIN;
		else
			type_max = (uint64_t)INT64_MAX;
		break;

	default:
		BHND_NV_LOG("unsupported integer type: %d\n", otype);
		return (EINVAL);
	}

	/* The maximum value after which an additional carry would overflow */
	value_max = type_max / (uint64_t)base;

	/* The maximum carry value given a value equal to value_max */
	carry_max = type_max % (uint64_t)base;

	/* Consume input until we hit maxlen or a non-digit character */
	for (; *nbytes < maxlen; (*nbytes)++) {
		u_long	carry;
		char	c;

		/* Parse carry value */
		c = str[*nbytes];
		if (bhnd_nv_isdigit(c)) {
			carry = c - '0';
		} else if (bhnd_nv_isxdigit(c)) {
			if (bhnd_nv_isupper(c))
				carry = (c - 'A') + 10;
			else
				carry = (c - 'a') + 10;
		} else {
			/* Hit first non-digit character */
			break;
		}

		/* If carry is outside the base, it's not a valid digit
		 * in the current parse context; consider it a non-digit
		 * character */
		if (carry >= (uint64_t)base)
			break;

		/* Increment count of parsed digits */
		ndigits++;

		if (value > value_max) {
			/* -Any- carry value would overflow */
			return (ERANGE);
		} else if (value == value_max && carry > carry_max) {
			/* -This- carry value would overflow */
			return (ERANGE);
		}

		value *= (uint64_t)base;
		value += carry;
	}

	/* If we hit a non-digit character before parsing the first digit,
	 * we hit an empty integer string. */
	if (ndigits == 0)
		return (EFTYPE);

	if (negative)
		value = -value;

	/* Provide (and verify) required length */
	*olen = bhnd_nvram_value_size(otype, NULL, 0, 1);
	if (outp == NULL)
		return (0);
	else if (limit < *olen)
		return (ENOMEM);

	/* Provide result */
	switch (otype) {
	case BHND_NVRAM_TYPE_CHAR:
	case BHND_NVRAM_TYPE_UINT8:
		*(uint8_t *)outp = (uint8_t)value;
		break;
	case BHND_NVRAM_TYPE_UINT16:
		*(uint16_t *)outp = (uint16_t)value;
		break;
	case BHND_NVRAM_TYPE_UINT32:
		*(uint32_t *)outp = (uint32_t)value;
		break;
	case BHND_NVRAM_TYPE_UINT64:
		*(uint64_t *)outp = (uint64_t)value;
		break;

	case BHND_NVRAM_TYPE_INT8:
		*(int8_t *)outp = (int8_t)(int64_t)value;
		break;
	case BHND_NVRAM_TYPE_INT16:
		*(int16_t *)outp = (int16_t)(int64_t)value;
		break;
	case BHND_NVRAM_TYPE_INT32:
		*(int32_t *)outp = (int32_t)(int64_t)value;
		break;
	case BHND_NVRAM_TYPE_INT64:
		*(int64_t *)outp = (int64_t)value;
		break;
	default:
		/* unreachable */
		BHND_NV_PANIC("unhandled type %d\n", otype);
	}

	return (0);
}
Ejemplo n.º 9
0
/**
 * Return the size, in bytes, of a value of @p type with @p nelem elements.
 * 
 * @param	type	The value type.
 * @param	data	The actual data to be queried, or NULL if unknown. If
 *			NULL and the base type is not a fixed width type
 *			(e.g. BHND_NVRAM_TYPE_STRING), 0 will be returned.
 * @param	nbytes	The size of @p data, in bytes, or 0 if @p data is NULL.
 * @param	nelem	The number of elements. If @p type is not an array type,
 *			this value must be 1.
 * 
 * @retval 0		If @p type has a variable width, and @p data is NULL.
 * @retval 0		If a @p nelem value greater than 1 is provided for a
 *			non-array @p type.
 * @retval 0		If a @p nelem value of 0 is provided.
 * @retval 0		If the result would exceed the maximum value
 *			representable by size_t.
 * @retval non-zero	The size, in bytes, of @p type with @p nelem elements.
 */
size_t
bhnd_nvram_value_size(bhnd_nvram_type type, const void *data, size_t nbytes,
    size_t nelem)
{
	/* If nelem 0, nothing to do */
	if (nelem == 0)
		return (0);

	/* Non-array types must have an nelem value of 1 */
	if (!bhnd_nvram_is_array_type(type) && nelem != 1)
		return (0);

	switch (type) {
	case BHND_NVRAM_TYPE_UINT8_ARRAY:
	case BHND_NVRAM_TYPE_UINT16_ARRAY:
	case BHND_NVRAM_TYPE_UINT32_ARRAY:
	case BHND_NVRAM_TYPE_UINT64_ARRAY:
	case BHND_NVRAM_TYPE_INT8_ARRAY:
	case BHND_NVRAM_TYPE_INT16_ARRAY:
	case BHND_NVRAM_TYPE_INT32_ARRAY:
	case BHND_NVRAM_TYPE_INT64_ARRAY:
	case BHND_NVRAM_TYPE_CHAR_ARRAY: {
		bhnd_nvram_type	base_type;
		size_t		base_size;

		base_type = bhnd_nvram_base_type(type);
		base_size = bhnd_nvram_value_size(base_type, NULL, 0, 1);

		/* Would nelem * base_size overflow? */
		if (SIZE_MAX / nelem < base_size) {
			BHND_NV_LOG("cannot represent size %s * %zu\n",
			    bhnd_nvram_type_name(base_type), nelem);
			return (0);
		}

		return (nelem * base_size);
	}

	case BHND_NVRAM_TYPE_STRING_ARRAY: {
		const char	*p;
		size_t		 total_size;

		if (data == NULL)
			return (0);

		/* Iterate over the NUL-terminated strings to calculate
		 * total byte length */
		p = data;
		total_size = 0;
		for (size_t i = 0; i < nelem; i++) {
			size_t	elem_size;

			elem_size = strnlen(p, nbytes - total_size);
			p += elem_size;

			/* Check for (and skip) terminating NUL */
			if (total_size < nbytes && *p == '\0') {
				elem_size++;
				p++;
			}

			/* Would total_size + elem_size overflow?
			 * 
			 * A memory range larger than SIZE_MAX shouldn't be,
			 * possible, but include the check for completeness */
			if (SIZE_MAX - total_size < elem_size)
				return (0);

			total_size += elem_size;
		}

		return (total_size);
	}

	case BHND_NVRAM_TYPE_STRING: {
		size_t size;

		if (data == NULL)
			return (0);

		/* Find length */
		size = strnlen(data, nbytes);

		/* Is there a terminating NUL, or did we just hit the
		 * end of the string input */
		if (size < nbytes)
			size++;

		return (size);
	}
	case BHND_NVRAM_TYPE_INT8:
	case BHND_NVRAM_TYPE_UINT8:
	case BHND_NVRAM_TYPE_CHAR:
		return (sizeof(uint8_t));

	case BHND_NVRAM_TYPE_INT16:
	case BHND_NVRAM_TYPE_UINT16:
		return (sizeof(uint16_t));

	case BHND_NVRAM_TYPE_INT32:
	case BHND_NVRAM_TYPE_UINT32:
		return (sizeof(uint32_t));

	case BHND_NVRAM_TYPE_UINT64:
	case BHND_NVRAM_TYPE_INT64:
		return (sizeof(uint64_t));
	}

	/* Quiesce gcc4.2 */
	BHND_NV_PANIC("bhnd nvram type %u unknown", type);
}
Ejemplo n.º 10
0
/**
 * Calculate the number of elements represented by a value of @p len bytes
 * with @p type.
 *
 * @param	type	The value type.
 * @param	data	The actual data to be queried, or NULL if unknown.
 * @param	len	The length in bytes of @p data, or if @p data is NULL,
 *			the expected length in bytes.
 * @param[out]	nelem	On success, the number of elements. If @p type is not
 *			a fixed width type (e.g. BHND_NVRAM_TYPE_STRING_ARRAY),
 *			and @p data is NULL, an @p nelem value of 0 will be
 *			returned.
 *
 * @retval 0		success
 * @retval EFTYPE	if @p type is not an array type, and @p len is not
 *			equal to the size of a single element of @p type.
 * @retval EFAULT	if @p len is not correctly aligned for elements of
 *			@p type.
 */
int
bhnd_nvram_value_nelem(bhnd_nvram_type type, const void *data, size_t len,
    size_t *nelem)
{
	bhnd_nvram_type	base_type;
	size_t		base_size;

	/* Length must be aligned to the element size */
	base_type = bhnd_nvram_base_type(type);
	base_size = bhnd_nvram_value_size(base_type, NULL, 0, 1);
	if (base_size != 0 && len % base_size != 0)
		return (EFAULT);

	switch (type) {
	case BHND_NVRAM_TYPE_STRING:
	case BHND_NVRAM_TYPE_STRING_ARRAY: {
		const char	*p;
		size_t		 nleft;

		/* Cannot determine the element count without parsing
		 * the actual data */
		if (data == NULL) {
			*nelem = 0;
			return (0);
		}

		/* Iterate over the NUL-terminated strings to calculate
		 * total element count */
		p = data;
		nleft = len;
		*nelem = 0;
		while (nleft > 0) {
			size_t slen;

			/* Increment element count */
			(*nelem)++;

			/* If not a string array, data must not contain more
			 * than one entry. */
			if (!bhnd_nvram_is_array_type(type) && *nelem > 1)
				return (EFTYPE);

			/* Determine string length */
			slen = strnlen(p, nleft);
			nleft -= slen;
	
			/* Advance input */
			p += slen;

			/* Account for trailing NUL, if we haven't hit the end
			 * of the input */
			if (nleft > 0) {
				nleft--;
				p++;
			}
		}

		return (0);
	}
	case BHND_NVRAM_TYPE_INT8:
	case BHND_NVRAM_TYPE_UINT8:
	case BHND_NVRAM_TYPE_CHAR:
	case BHND_NVRAM_TYPE_INT16:
	case BHND_NVRAM_TYPE_UINT16:
	case BHND_NVRAM_TYPE_INT32:
	case BHND_NVRAM_TYPE_UINT32:
	case BHND_NVRAM_TYPE_INT64:
	case BHND_NVRAM_TYPE_UINT64:
		/* Length must be equal to the size of exactly one
		 * element (arrays can represent zero elements -- non-array
		 * types cannot) */
		if (len != base_size)
			return (EFTYPE);
		*nelem = 1;
		return (0);

	case BHND_NVRAM_TYPE_UINT8_ARRAY:
	case BHND_NVRAM_TYPE_UINT16_ARRAY:
	case BHND_NVRAM_TYPE_UINT32_ARRAY:
	case BHND_NVRAM_TYPE_UINT64_ARRAY:
	case BHND_NVRAM_TYPE_INT8_ARRAY:
	case BHND_NVRAM_TYPE_INT16_ARRAY:
	case BHND_NVRAM_TYPE_INT32_ARRAY:
	case BHND_NVRAM_TYPE_INT64_ARRAY:
	case BHND_NVRAM_TYPE_CHAR_ARRAY:
		BHND_NV_ASSERT(base_size != 0, ("invalid base size"));
		*nelem = len / base_size;
		return (0);
	}

	/* Quiesce gcc4.2 */
	BHND_NV_PANIC("bhnd nvram type %u unknown", type);
}