/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" /* * This file contains kernel property decode routines adopted from * sunddi.c and ddi_impl.c. The following changes have been applied. * * (1) Replace kmem_alloc by malloc. Remove negative indexing * (2) Decoding applies only to prom properties. * (3) For strings, the return value is a composite string, not a string array. * (4) impl_ddi_prop_int_from_prom() uses _LITTLE_ENDIAN from isa_defs.h * * XXX This file should be kept in sync with kernel property encoding. */ #include #include #include #include #include #include #include #include #include "libdevinfo.h" /* * Return an integer in native machine format from an OBP 1275 integer * representation, which is big-endian, with no particular alignment * guarantees. intp points to the OBP data, and n the number of bytes. * * Byte-swapping may be needed on some implementations. */ int impl_di_prop_int_from_prom(uchar_t *intp, int n) { int i = 0; #if defined(_LITTLE_ENDIAN) intp += n; while (n-- > 0) { i = (i << 8) | *(--intp); } #else while (n-- > 0) { i = (i << 8) | *intp++; } #endif /* defined(_LITTLE_ENDIAN) */ return (i); } /* * Reset the current location pointer in the property handle to the * beginning of the data. */ void di_prop_reset_pos(prop_handle_t *ph) { ph->ph_cur_pos = ph->ph_data; ph->ph_save_pos = ph->ph_data; } /* * Restore the current location pointer in the property handle to the * saved position. */ void di_prop_save_pos(prop_handle_t *ph) { ph->ph_save_pos = ph->ph_cur_pos; } /* * Save the location that the current location poiner is pointing to.. */ void di_prop_restore_pos(prop_handle_t *ph) { ph->ph_cur_pos = ph->ph_save_pos; } /* * Property encode/decode functions */ /* * Decode an array of integers property */ static int di_prop_fm_decode_ints(prop_handle_t *ph, void *data, uint_t *nelements) { int i; int cnt = 0; int *tmp; int *intp; int n; /* * Figure out how many array elements there are by going through the * data without decoding it first and counting. */ for (;;) { i = DDI_PROP_INT(ph, DDI_PROP_CMD_SKIP, NULL); if (i < 0) break; cnt++; } /* * If there are no elements return an error */ if (cnt == 0) return (DDI_PROP_END_OF_DATA); /* * If we cannot skip through the data, we cannot decode it */ if (i == DDI_PROP_RESULT_ERROR) return (DDI_PROP_CANNOT_DECODE); /* * Reset the data pointer to the beginning of the encoded data */ di_prop_reset_pos(ph); /* * Allocated memory to store the decoded value in. */ if ((intp = malloc(cnt * sizeof (int))) == NULL) { return (DDI_PROP_CANNOT_DECODE); } /* * Decode each elemente and place it in the space we just allocated */ tmp = intp; for (n = 0; n < cnt; n++, tmp++) { i = DDI_PROP_INT(ph, DDI_PROP_CMD_DECODE, tmp); if (i < DDI_PROP_RESULT_OK) { /* * Free the space we just allocated * and return an error. */ free(intp); switch (i) { case DDI_PROP_RESULT_EOF: return (DDI_PROP_END_OF_DATA); case DDI_PROP_RESULT_ERROR: return (DDI_PROP_CANNOT_DECODE); } } } *nelements = cnt; *(int **)data = intp; return (DDI_PROP_SUCCESS); } /* * Decode an array of strings. */ static int di_prop_fm_decode_strings(prop_handle_t *ph, void *data, uint_t *nelements) { int cnt = 0; char *strs; char *tmp; int size; int i; int n; int nbytes; /* * Figure out how much memory we need for the sum total */ nbytes = 0; for (;;) { /* * Get the decoded size of the current encoded string. */ size = DDI_PROP_STR(ph, DDI_PROP_CMD_GET_DSIZE, NULL); if (size < 0) break; cnt++; nbytes += size; } /* * If there are no elements return an error */ if (cnt == 0) return (DDI_PROP_END_OF_DATA); /* * If we cannot skip through the data, we cannot decode it */ if (size == DDI_PROP_RESULT_ERROR) return (DDI_PROP_CANNOT_DECODE); /* * Allocate memory in which to store the decoded strings. */ if ((strs = malloc(nbytes)) == NULL) { return (DDI_PROP_CANNOT_DECODE); } /* * Finally, we can decode each string */ di_prop_reset_pos(ph); tmp = strs; for (n = 0; n < cnt; n++) { i = DDI_PROP_STR(ph, DDI_PROP_CMD_DECODE, tmp); if (i < DDI_PROP_RESULT_OK) { /* * Free the space we just allocated * and return an error */ free(strs); switch (i) { case DDI_PROP_RESULT_EOF: return (DDI_PROP_END_OF_DATA); case DDI_PROP_RESULT_ERROR: return (DDI_PROP_CANNOT_DECODE); } } tmp += strlen(tmp) + 1; } *(char **)data = strs; *nelements = cnt; return (DDI_PROP_SUCCESS); } /* * Decode an array of bytes. */ static int di_prop_fm_decode_bytes(prop_handle_t *ph, void *data, uint_t *nelements) { uchar_t *tmp; int nbytes; int i; /* * If there are no elements return an error */ if (ph->ph_size == 0) return (DDI_PROP_END_OF_DATA); /* * Get the size of the encoded array of bytes. */ nbytes = DDI_PROP_BYTES(ph, DDI_PROP_CMD_GET_DSIZE, data, ph->ph_size); if (nbytes < DDI_PROP_RESULT_OK) { switch (nbytes) { case DDI_PROP_RESULT_EOF: return (DDI_PROP_END_OF_DATA); case DDI_PROP_RESULT_ERROR: return (DDI_PROP_CANNOT_DECODE); } } /* * Allocated memory to store the decoded value in. */ if ((tmp = malloc(nbytes)) == NULL) { return (DDI_PROP_CANNOT_DECODE); } /* * Decode each element and place it in the space we just allocated */ i = DDI_PROP_BYTES(ph, DDI_PROP_CMD_DECODE, tmp, nbytes); if (i < DDI_PROP_RESULT_OK) { /* * Free the space we just allocated * and return an error */ free(tmp); switch (i) { case DDI_PROP_RESULT_EOF: return (DDI_PROP_END_OF_DATA); case DDI_PROP_RESULT_ERROR: return (DDI_PROP_CANNOT_DECODE); } } *(uchar_t **)data = tmp; *nelements = nbytes; return (DDI_PROP_SUCCESS); } /* * OBP 1275 integer, string and byte operators. * * DDI_PROP_CMD_DECODE: * * DDI_PROP_RESULT_ERROR: cannot decode the data * DDI_PROP_RESULT_EOF: end of data * DDI_PROP_OK: data was decoded * * DDI_PROP_CMD_ENCODE: * * DDI_PROP_RESULT_ERROR: cannot encode the data * DDI_PROP_RESULT_EOF: end of data * DDI_PROP_OK: data was encoded * * DDI_PROP_CMD_SKIP: * * DDI_PROP_RESULT_ERROR: cannot skip the data * DDI_PROP_RESULT_EOF: end of data * DDI_PROP_OK: data was skipped * * DDI_PROP_CMD_GET_ESIZE: * * DDI_PROP_RESULT_ERROR: cannot get encoded size * DDI_PROP_RESULT_EOF: end of data * > 0: the encoded size * * DDI_PROP_CMD_GET_DSIZE: * * DDI_PROP_RESULT_ERROR: cannot get decoded size * DDI_PROP_RESULT_EOF: end of data * > 0: the decoded size */ /* * OBP 1275 integer operator * * OBP properties are a byte stream of data, so integers may not be * properly aligned. Therefore we need to copy them one byte at a time. */ int di_prop_1275_int(prop_handle_t *ph, uint_t cmd, int *data) { int i; switch (cmd) { case DDI_PROP_CMD_DECODE: /* * Check that there is encoded data */ if (ph->ph_cur_pos == NULL || ph->ph_size == 0) return (DDI_PROP_RESULT_ERROR); if (ph->ph_flags & PH_FROM_PROM) { i = ph->ph_size < PROP_1275_INT_SIZE ? ph->ph_size : PROP_1275_INT_SIZE; if ((int *)ph->ph_cur_pos > ((int *)ph->ph_data + ph->ph_size - i)) return (DDI_PROP_RESULT_ERROR); } else if (ph->ph_size < sizeof (int) || ((int *)ph->ph_cur_pos > ((int *)ph->ph_data + ph->ph_size - sizeof (int)))) { return (DDI_PROP_RESULT_ERROR); } /* * Copy the integer, using the implementation-specific * copy function if the property is coming from the PROM. */ if (ph->ph_flags & PH_FROM_PROM) { *data = impl_di_prop_int_from_prom( (uchar_t *)ph->ph_cur_pos, (ph->ph_size < PROP_1275_INT_SIZE) ? ph->ph_size : PROP_1275_INT_SIZE); } else { bcopy(ph->ph_cur_pos, (caddr_t)data, sizeof (int)); } /* * Move the current location to the start of the next * bit of undecoded data. */ ph->ph_cur_pos = (uchar_t *)ph->ph_cur_pos + PROP_1275_INT_SIZE; return (DDI_PROP_RESULT_OK); case DDI_PROP_CMD_ENCODE: /* * Check that there is room to encoded the data */ if (ph->ph_cur_pos == NULL || ph->ph_size == 0 || ph->ph_size < PROP_1275_INT_SIZE || ((int *)ph->ph_cur_pos > ((int *)ph->ph_data + ph->ph_size - sizeof (int)))) return (DDI_PROP_RESULT_ERROR); /* * Encode the integer into the byte stream one byte at a * time. */ bcopy((caddr_t)data, ph->ph_cur_pos, sizeof (int)); /* * Move the current location to the start of the next bit of * space where we can store encoded data. */ ph->ph_cur_pos = (uchar_t *)ph->ph_cur_pos + PROP_1275_INT_SIZE; return (DDI_PROP_RESULT_OK); case DDI_PROP_CMD_SKIP: /* * Check that there is encoded data */ if (ph->ph_cur_pos == NULL || ph->ph_size == 0 || ph->ph_size < PROP_1275_INT_SIZE) return (DDI_PROP_RESULT_ERROR); if ((caddr_t)ph->ph_cur_pos == (caddr_t)ph->ph_data + ph->ph_size) { return (DDI_PROP_RESULT_EOF); } else if ((caddr_t)ph->ph_cur_pos > (caddr_t)ph->ph_data + ph->ph_size) { return (DDI_PROP_RESULT_EOF); } /* * Move the current location to the start of the next bit of * undecoded data. */ ph->ph_cur_pos = (uchar_t *)ph->ph_cur_pos + PROP_1275_INT_SIZE; return (DDI_PROP_RESULT_OK); case DDI_PROP_CMD_GET_ESIZE: /* * Return the size of an encoded integer on OBP */ return (PROP_1275_INT_SIZE); case DDI_PROP_CMD_GET_DSIZE: /* * Return the size of a decoded integer on the system. */ return (sizeof (int)); } /*NOTREACHED*/ return (0); /* keep gcc happy */ } /* * 64 bit integer operator * * This is an extension, defined by Sun, to the 1275 integer * operator. This routine handles the encoding/decoding of * 64 bit integer properties. */ int di_prop_int64_op(prop_handle_t *ph, uint_t cmd, int64_t *data) { switch (cmd) { case DDI_PROP_CMD_DECODE: /* * Check that there is encoded data */ if (ph->ph_cur_pos == NULL || ph->ph_size == 0) return (DDI_PROP_RESULT_ERROR); if (ph->ph_flags & PH_FROM_PROM) { return (DDI_PROP_RESULT_ERROR); } else if (ph->ph_size < sizeof (int64_t) || ((int64_t *)ph->ph_cur_pos > ((int64_t *)ph->ph_data + ph->ph_size - sizeof (int64_t)))) { return (DDI_PROP_RESULT_ERROR); } /* * Copy the integer, using the implementation-specific * copy function if the property is coming from the PROM. */ bcopy(ph->ph_cur_pos, (caddr_t)data, sizeof (int64_t)); /* * Move the current location to the start of the next * bit of undecoded data. */ ph->ph_cur_pos = (uchar_t *)ph->ph_cur_pos + sizeof (int64_t); return (DDI_PROP_RESULT_OK); case DDI_PROP_CMD_ENCODE: /* * Check that there is room to encoded the data */ if (ph->ph_cur_pos == NULL || ph->ph_size == 0 || ph->ph_size < sizeof (int64_t) || ((int64_t *)ph->ph_cur_pos > ((int64_t *)ph->ph_data + ph->ph_size - sizeof (int64_t)))) return (DDI_PROP_RESULT_ERROR); /* * Encode the integer into the byte stream one byte at a * time. */ bcopy((caddr_t)data, ph->ph_cur_pos, sizeof (int64_t)); /* * Move the current location to the start of the next bit of * space where we can store encoded data. */ ph->ph_cur_pos = (uchar_t *)ph->ph_cur_pos + sizeof (int64_t); return (DDI_PROP_RESULT_OK); case DDI_PROP_CMD_SKIP: /* * Check that there is encoded data */ if (ph->ph_cur_pos == NULL || ph->ph_size == 0 || ph->ph_size < sizeof (int64_t)) return (DDI_PROP_RESULT_ERROR); if ((caddr_t)ph->ph_cur_pos == (caddr_t)ph->ph_data + ph->ph_size) { return (DDI_PROP_RESULT_EOF); } else if ((caddr_t)ph->ph_cur_pos > (caddr_t)ph->ph_data + ph->ph_size) { return (DDI_PROP_RESULT_EOF); } /* * Move the current location to the start of the next bit of * undecoded data. */ ph->ph_cur_pos = (uchar_t *)ph->ph_cur_pos + sizeof (int64_t); return (DDI_PROP_RESULT_OK); case DDI_PROP_CMD_GET_ESIZE: /* * Return the size of an encoded integer on OBP */ return (sizeof (int64_t)); case DDI_PROP_CMD_GET_DSIZE: /* * Return the size of a decoded integer on the system. */ return (sizeof (int64_t)); } /*NOTREACHED*/ return (0); /* keep gcc happy */ } /* * OBP 1275 string operator. * * OBP strings are NULL terminated. */ int di_prop_1275_string(prop_handle_t *ph, uint_t cmd, char *data) { int n; char *p; char *end; switch (cmd) { case DDI_PROP_CMD_DECODE: /* * Check that there is encoded data */ if (ph->ph_cur_pos == NULL || ph->ph_size == 0) { return (DDI_PROP_RESULT_ERROR); } n = strlen((char *)ph->ph_cur_pos) + 1; if ((char *)ph->ph_cur_pos > ((char *)ph->ph_data + ph->ph_size - n)) { return (DDI_PROP_RESULT_ERROR); } /* * Copy the NULL terminated string */ bcopy((char *)ph->ph_cur_pos, data, n); /* * Move the current location to the start of the next bit of * undecoded data. */ ph->ph_cur_pos = (char *)ph->ph_cur_pos + n; return (DDI_PROP_RESULT_OK); case DDI_PROP_CMD_ENCODE: /* * Check that there is room to encoded the data */ if (ph->ph_cur_pos == NULL || ph->ph_size == 0) { return (DDI_PROP_RESULT_ERROR); } n = strlen(data) + 1; if ((char *)ph->ph_cur_pos > ((char *)ph->ph_data + ph->ph_size - n)) { return (DDI_PROP_RESULT_ERROR); } /* * Copy the NULL terminated string */ bcopy(data, (char *)ph->ph_cur_pos, n); /* * Move the current location to the start of the next bit of * space where we can store encoded data. */ ph->ph_cur_pos = (char *)ph->ph_cur_pos + n; return (DDI_PROP_RESULT_OK); case DDI_PROP_CMD_SKIP: /* * Check that there is encoded data */ if (ph->ph_cur_pos == NULL || ph->ph_size == 0) { return (DDI_PROP_RESULT_ERROR); } /* * Return the string length plus one for the NULL * We know the size of the property, we need to * ensure that the string is properly formatted, * since we may be looking up random OBP data. */ p = (char *)ph->ph_cur_pos; end = (char *)ph->ph_data + ph->ph_size; if (p == end) { return (DDI_PROP_RESULT_EOF); } /* * Make sure each char is printable */ for (n = 0; p < end && isascii(*p) && !iscntrl(*p); n++, p++) ; /* Check termination and non-zero length */ if ((*p == 0) && (n != 0)) { ph->ph_cur_pos = p + 1; return (DDI_PROP_RESULT_OK); } return (DDI_PROP_RESULT_ERROR); case DDI_PROP_CMD_GET_ESIZE: /* * Return the size of the encoded string on OBP. */ return (strlen(data) + 1); case DDI_PROP_CMD_GET_DSIZE: /* * Return the string length plus one for the NULL * We know the size of the property, we need to * ensure that the string is properly formatted, * since we may be looking up random OBP data. */ p = (char *)ph->ph_cur_pos; end = (char *)ph->ph_data + ph->ph_size; for (n = 0; p < end; n++) { if (*p++ == '\0') { ph->ph_cur_pos = p; return (n+1); } } /* * Add check here to separate EOF and ERROR. */ if (p == end) return (DDI_PROP_RESULT_EOF); return (DDI_PROP_RESULT_ERROR); } /*NOTREACHED*/ return (0); /* keep gcc happy */ } /* * OBP 1275 byte operator * * Caller must specify the number of bytes to get. OBP encodes bytes * as a byte so there is a 1-to-1 translation. */ int di_prop_1275_bytes(prop_handle_t *ph, uint_t cmd, uchar_t *data, uint_t nelements) { switch (cmd) { case DDI_PROP_CMD_DECODE: /* * Check that there is encoded data */ if (ph->ph_cur_pos == NULL || ph->ph_size == 0 || ph->ph_size < nelements || ((char *)ph->ph_cur_pos > ((char *)ph->ph_data + ph->ph_size - nelements))) return (DDI_PROP_RESULT_ERROR); /* * Copy out the bytes */ bcopy((char *)ph->ph_cur_pos, (char *)data, nelements); /* * Move the current location */ ph->ph_cur_pos = (char *)ph->ph_cur_pos + nelements; return (DDI_PROP_RESULT_OK); case DDI_PROP_CMD_ENCODE: /* * Check that there is room to encode the data */ if (ph->ph_cur_pos == NULL || ph->ph_size == 0 || ph->ph_size < nelements || ((char *)ph->ph_cur_pos > ((char *)ph->ph_data + ph->ph_size - nelements))) return (DDI_PROP_RESULT_ERROR); /* * Copy in the bytes */ bcopy((char *)data, (char *)ph->ph_cur_pos, nelements); /* * Move the current location to the start of the next bit of * space where we can store encoded data. */ ph->ph_cur_pos = (char *)ph->ph_cur_pos + nelements; return (DDI_PROP_RESULT_OK); case DDI_PROP_CMD_SKIP: /* * Check that there is encoded data */ if (ph->ph_cur_pos == NULL || ph->ph_size == 0 || ph->ph_size < nelements) return (DDI_PROP_RESULT_ERROR); if ((char *)ph->ph_cur_pos > ((char *)ph->ph_data + ph->ph_size - nelements)) return (DDI_PROP_RESULT_EOF); /* * Move the current location */ ph->ph_cur_pos = (char *)ph->ph_cur_pos + nelements; return (DDI_PROP_RESULT_OK); case DDI_PROP_CMD_GET_ESIZE: /* * The size in bytes of the encoded size is the * same as the decoded size provided by the caller. */ return (nelements); case DDI_PROP_CMD_GET_DSIZE: /* * Just return the number of bytes specified by the caller. */ return (nelements); } /*NOTREACHED*/ return (0); /* keep gcc happy */ } /* * Used for properties that come from the OBP, hardware configuration files, * or that are created by calls to ddi_prop_update(9F). */ static struct prop_handle_ops prop_1275_ops = { di_prop_1275_int, di_prop_1275_string, di_prop_1275_bytes, di_prop_int64_op }; /* * Now the real thing: * Extract type-specific values of an property */ int di_prop_decode_common(void *data, int size, int prop_type, int prom) { int n; int nelements; char *cp, *end; prop_handle_t ph; int (*prop_decoder)(prop_handle_t *, void *, uint_t *); /* * If the encoded data came from software, no decoding needed */ if (!prom) { switch (prop_type) { case DI_PROP_TYPE_INT: if (size % sizeof (int)) nelements = -1; else nelements = size / sizeof (int); break; case DI_PROP_TYPE_INT64: if (size % sizeof (int64_t)) nelements = -1; else nelements = size / sizeof (int64_t); break; case DI_PROP_TYPE_STRING: nelements = 0; cp = *(char **)data; end = cp + size; /* * Don't trust the data passed in by the caller. * Check every char to make sure it is indeed a * string property. */ while (cp < end) { /* skip to next non-printable char */ for (n = 0; cp < end && isascii(*cp) && !iscntrl(*cp); n++, cp++) ; /* * Fail if reached end (i.e. last char != 0), * or has a non-printable char. A zero length * string is acceptable. */ if (cp == end || *cp != 0) { nelements = -1; break; } /* * Increment # strings and keep going */ nelements++; cp++; } break; case DI_PROP_TYPE_BYTE: nelements = size; } return (nelements); } /* * Get the encoded data */ bzero((caddr_t)&ph, sizeof (prop_handle_t)); ph.ph_data = *(uchar_t **)data; ph.ph_size = size; /* * The data came from prom, use the 1275 OBP decode/encode routines. */ ph.ph_cur_pos = ph.ph_data; ph.ph_save_pos = ph.ph_data; ph.ph_ops = &prop_1275_ops; ph.ph_flags = PH_FROM_PROM; switch (prop_type) { case DI_PROP_TYPE_INT: prop_decoder = di_prop_fm_decode_ints; break; case DI_PROP_TYPE_STRING: prop_decoder = di_prop_fm_decode_strings; break; case DI_PROP_TYPE_BYTE: default: prop_decoder = di_prop_fm_decode_bytes; break; } if ((*prop_decoder)(&ph, data, (uint_t *)&nelements) != DDI_PROP_SUCCESS) return (-1); /* * Free the encoded data */ if (size != 0) free(ph.ph_data); return (nelements); } void di_slot_names_free(int count, di_slot_name_t *slot_names) { if (slot_names == NULL) return; while (--count >= 0) { if (slot_names[count].name != NULL) free(slot_names[count].name); } free(slot_names); } /* * 1275 "slot-names" format: [int][string1][string2]...[stringN] * - [int] is a 1275 encoded integer * - [string1]...[stringN] are concatenated null-terminated strings * - each bit position in [int] represents a pci device number * - each bit which is set in [int] represents a slot with a device * number of that bit position * - each string in [string1]...[stringN] identifies a slot name only * for the bits which are set in [int] * - the ordering of strings follow the ordering of bits set in [int] * * an allocated array of di_slot_name_t is returned through prop_data if * [int] is non-zero and the number of entries as the return value; * use di_slot_names_free() to free the array */ int di_slot_names_decode(uchar_t *rawdata, int rawlen, di_slot_name_t **prop_data) { char *sp, *maxsp; int count, i; size_t len; int slots; int maxcount = 0; int maxslots = 0; di_slot_name_t *slot_names = NULL; if (rawlen < sizeof (slots)) goto ERROUT; slots = impl_di_prop_int_from_prom(rawdata, sizeof (slots)); if (slots == 0) { *prop_data = NULL; return (0); } maxslots = sizeof (slots) * 8; count = 0; for (i = 0; i < maxslots; i++) { if (slots & (1 << i)) count++; } maxslots = i; maxcount = count; slot_names = malloc(sizeof (*slot_names) * maxcount); bzero(slot_names, sizeof (*slot_names) * maxcount); /* also handle unterminated strings */ sp = (char *)(rawdata + sizeof (slots)); maxsp = sp + (rawlen - sizeof (slots)); count = 0; for (i = 0; i < maxslots; i++) { if (slots & (1 << i)) { if (sp > maxsp) break; len = strnlen(sp, (maxsp - sp) + 1); if (len == 0) break; slot_names[count].name = malloc(sizeof (char) * (len + 1)); (void) strlcpy(slot_names[count].name, sp, len + 1); slot_names[count].num = i; sp += len + 1; count++; } } /* * check if the number of strings match with the number of slots; * we can also get a lesser string count even when there appears to be * the correct number of strings if one or more pair of strings are * seperated by more than one NULL byte */ if (count != maxcount) goto ERROUT; *prop_data = slot_names; return (maxcount); /*NOTREACHED*/ ERROUT: di_slot_names_free(maxcount, slot_names); *prop_data = NULL; return (-1); }