/** * 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); }
/** * 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); }
/** * 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); }
/** * 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); }
/** * 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); }
/** * 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); }
/** * 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); }
/** * 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); }
/** * 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); }
/** * 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); }