/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (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
* 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 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* diagcode library, Sun Private API (PSARC/2004/601)
*
* undocumented debugging interface:
* set environment variable _FM_DC_DEBUG for debug prints to stderr.
* set it to 1 for extended error messages only.
* set it to 2 to include success info too on interesting functions.
* set it to 3 to include success info on trivial functions too.
* note that this environment variable is only examined in fm_dc_opendict().
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <alloca.h>
#include <errno.h>
#include <fm/diagcode.h>
/* private (opaque to callers) handle information */
struct fm_dc_handle {
const char *dictname;
unsigned maxkey;
int version;
int debug;
struct fm_dc_prop {
const char *lhs;
const char *rhs;
} *props;
};
/*
* parameters of the various sizes of diagcodes
*
* table must be in ascending order from smallest databits value to largest.
* when faced with more databits than the last entry, we know we have
* something that won't fit into a diagcode.
*/
static const struct info {
} Info[] = {
/* diagcode is: dictname-XXXX-XX */
/* diagcode is: dictname-XXXX-XXXX-XX */
{ 38, 10, 8, 1, 2097152ULL },
/* diagcode is: dictname-XXXX-XXXX-XXXX-XX */
{ 55, 14, 11, 2, 274880004096ULL },
/* diagcode is: dictname-XXXX-XXXX-XXXX-XXXX-XX */
{ 72, 18, 14, 3, 36029071898968064ULL }
};
/* forward references for functions private to this file */
struct parsestate {
};
static bitv *bitv_alloc(void);
/* properties we look for at top of dictionary */
/* the alphabet used to encode information in a diagcode (base32 digits) */
/* open a dictionary, return opaque handle */
{
/* undocumented flag, given via environment variable */
if (debug > 1)
"fm_dc_opendict: ver %d path \"%s\" dict \"%s\": ",
else if (debug)
/* verify caller expects an API version we support */
if (debug)
return (NULL);
}
/* caller can pass in NULL for default dirpath */
/*
* allocate buffer for dirpath, slash, dictname, and suffix
* (sizeof (Suffix) includes the null).
*/
/*
* allocate the handle.
*
* allocate the dictname copy kept in the handle.
*
* if any of these fail, send back ENOMEM.
*/
if (dhp)
if (debug)
return (NULL);
}
/* initialize the handle */
/* open the dictionary */
if (debug > 1)
if (debug > 1)
perror("fopen");
else if (debug) {
perror("fopen");
}
return (NULL);
}
/* pull in the header line and parse it */
line++;
continue;
/* first non-comment, non-blank line must be header */
if (debug)
"%sEINVAL: line %d: header expected.\n",
return (NULL);
}
/* just wanted header line for now */
break;
}
/* walk through name=value pairs in line after Header string */
if (debug)
return (NULL);
}
if (debug)
}
return (NULL);
}
}
/*
* require version 1, expected dict name, and maxkey values
* (note we use "1" here and not FM_DC_VERSION because this code
* implements version 1, so the check below should not float to
* newer version numbers if the header file defines them.)
*/
if (debug)
"%sEINVAL ver %d name \"%s\" maxkey %d\n",
return (NULL);
}
if (debug > 1)
(void *)dhp);
return (dhp);
}
/* close a dictionary */
void
{
(void *)dhp);
while (props) {
}
}
/* return maximum length (in bytes) of diagcodes for a given dictionary */
{
/* only one version so far, so dhp->version isn't checked */
return (len + MAXCODELEN);
}
/* return number of strings in key for a given dictionary */
int
{
/* only one version so far, so dhp->version isn't checked */
/* this interface counts the NULL entry */
}
/* given a key, construct a diagcode */
int
{
/* only one version so far, so dhp->version isn't checked */
int nel;
"fm_dc_key2code: dhp 0x%p maxcode %lu ", (void *)dhp,
debugstr = "fm_dc_key2code: ";
/* sort the keys */
line++;
continue;
/* first non-comment, non-blank line must be header */
continue;
else {
"fm_dc_key2code: dictionary line %d",
line);
}
}
}
/* no match */
return (-1);
}
/* given a diagcode, return the key (array of strings) */
int
{
int line = 0;
/* only one version so far, so dhp->version isn't checked */
"fm_dc_code2key: dhp 0x%p code \"%s\" maxkey %d: ",
debugstr = "fm_dc_code2key: ";
/* convert code back to bit vector */
/* code2dictval() sets errno */
/* handle expected types without printing a number */
"%sENOMEM code2dictval\n",
debugstr);
"%sEINVAL code2dictval\n",
debugstr);
else
"%scode2dictval error %d\n",
}
return (-1);
}
char *ptr;
char *beginp;
char *endp;
int nel;
line++;
continue;
/* first non-comment, non-blank line must be header */
continue;
continue; /* ignore malformed entries */
*ptr++ = '\0';
/* pull in value from dictionary */
/* bitv_strparse() sets errno */
"%sENOMEM bitv_strparse\n",
debugstr);
return (-1);
}
/* other than ENOMEM, trudge on... */
continue;
}
continue;
}
/* if we got here, we found the match */
nel = 0;
for (;;) {
beginp++;
if (*beginp == '\0') {
/* all done */
return (0);
}
"%sENOMEM maxkey %d\n",
return (-1);
}
;
if (*endp)
*endp++ = '\0';
"%sENOMEM strdup\n", debugstr);
return (-1);
}
}
}
return (-1);
}
/* return the right-hand side of a names property from the dict header */
const char *
{
/* only one version so far, so dhp->version isn't checked */
break;
}
/* find the appropriate diagcode format for a given dictval */
static const struct info *
{
int i;
return (&Info[i]);
/* return largest format */
}
/* lookup the diagcode parameters given the number of X's used */
static const struct info *
{
int i;
return (&Info[i]);
return (NULL);
}
/* for use with qsort() */
static int
mycmp(const void *a, const void *b)
{
return (strcmp(*(char **)a, *(char **)b));
}
/*
* sortkey -- make sure key[] array is lexically sorted and without repeats
*/
static void
{
int nel;
/* count the number of elements in key[] */
;
if (nel < 2)
return; /* nothing to sort */
/* go through array and remove repeats */
dsti = 1;
}
/*
* keymatch -- check for matching line from the dictionary
*
* assumes that the key[] array has already been lexically sorted.
* returns NULL if no match, otherwise pointer to first character of RHS.
*/
static const char *
{
int keynum = 0;
const char *ptr;
while (linebuf) {
/* skip any initial whitespace in front of name */
linebuf++;
/* match */
linebuf++;
linebuf++;
return (linebuf);
return (NULL); /* dict had more strings for key */
/* match the string */
while (*linebuf)
if (*ptr == '\0') {
break; /* match */
else
return (NULL); /* dict string longer */
return (NULL); /* string don't match */
else {
linebuf++;
ptr++;
}
keynum++;
}
return (NULL); /* no match */
}
/*
* buildcode -- given the val from the dictionary, create the diagcode
*/
static int
{
const char *ptr;
/* sanity check that buffer is large enough for diagcode */
"%sENOMEM maxcode %lu < codelen %lu\n",
return (-1);
}
/* handle dictname part of checksum */
}
/* pull in value from dictionary */
/* bitv_strparse() sets errno */
/* handle expected types without printing a number */
"%sENOMEM bitv_strparse\n",
debugstr);
"%sERANGE bitv_strparse\n",
debugstr);
else
"%sbitv_strparse error %d\n",
}
return (-1);
}
/* determine which format of code we're using */
/* subtract off the offset appropriate for format of code */
/*
* this "cannot happen" since code format was chosen
* so that offset will be smaller than dictval, and
* dictval cannot be out of range since bitv_strparse()
* should have caught it.
*/
"%sERANGE from bitv_sub\n", debugstr);
return (-1);
}
/* assemble all the bits for the diagcode */
"%sENOMEM from bitv_alloc\n", debugstr);
return (-1);
}
/*
* construct the full diagcode by shifting in information:
* - 2 bit code type, set to 01
* - 2 bit size field
* - the databits of the dictionary code itself
*/
/* insert zeros for checksum */
/* compute checksum */
limbit -= 5;
}
/* insert the computed checksum */
/* encode binary values according to alphabet */
if (bit % 4 == 0)
*code++ = '-';
limbit -= 5;
}
*code = '\0';
return (0);
}
/*
* code2dictval -- convert a diagcode back to a bit vector
*/
static bitv *
{
const char *ptr;
/* check dictname part of code */
return (NULL);
}
/* convert code back to a bit vector */
return (NULL);
}
/* we verified it began with dictname and a dash, so skip it */
numx = 0;
/* be forgiving about misplaced dashes */
if (*code == '-')
continue;
else {
unsigned val;
break;
return (NULL);
}
numx++;
}
return (NULL);
}
/* now pull out the csum */
/* set the csum bits to zero */
/* calculate the checksum and see if it matches */
csum = 0;
limbit -= 5;
}
return (NULL);
}
/* code looks okay, just return dictval portion */
return (NULL);
}
limbit--;
}
/* add in the offset appropriate for the length of code being used */
/*
* overflow "cannot happen" since we've pulled in
* a given number of bits from the code and the offset
* is designed not to overflow...
*/
return (NULL);
}
return (dictval);
}
/*
*
*/
/*
* startparse -- record starting of buffer containing name=value pairs
*/
static void
{
}
/*
* nextlhs -- return next left-hand-side of name=value pair, or NULL
*
* whitespace around the '=' is allowed for, but not required. the
* lhs is a simple string that does not contain any whitespace or an
* embedded equals sign. no escaped characters, quotes, etc. are
* honored here.
*
* this routine also parses the rhs and saves a pointer to it
* in Rhsp so that nextrhs() can return it. if nextrhs() never
* gets called, we continue looking for the next lhs *after* any
* rhs that was there.
*/
static char *
{
char *lhsp;
char *copyto;
int equals = 0;
int quote = 0;
int backslash = 0;
/* skip whitespace */
/* anything left? */
return (NULL);
/* remember start of lhs, assume no rhs until we see '=' */
/* find end of token, no escaped chars, quotes, etc. on lhs */
equals = 1;
break;
} else
/* null terminate the token, possibly nuking the '=' itself */
/* if we haven't seen an '=', see if it happens after whitespace */
if (!equals) {
equals = 1;
}
}
/* skip whitespace */
/* isolate the rhs if it is there */
return (lhsp);
}
quote = 1;
}
/* remember the beginning of the rhs */
/* now scan to the end of the rhs */
if (backslash) {
case 't':
*copyto++ = '\t';
break;
case 'r':
*copyto++ = '\r';
break;
case 'n':
*copyto++ = '\n';
break;
case 'f':
*copyto++ = '\f';
break;
default:
break;
}
backslash = 0;
backslash = 1;
else if (quote) {
break; /* end of quoted string */
} else
else {
break; /* rhs terminated by whitespace */
}
}
*copyto = '\0';
return (lhsp);
}
/*
* nextrhs -- return right-hand-side of name=value pair, or NULL
*
* this routine can only be used after a lhs has been found with
* nextlhs(). the rhs consists of a string with no whitespace in it,
* unless the whitespace is escaped with a backslash. surrounding
* a string with double quotes is also supported here, as are the
* common C escape sequences like \t and \n.
*
* nextlhs() actually does all the hard work. we just return any
* rhs that was found by that routine.
*/
static char *
{
}
/*
* private routines to manipulate bit vectors (i.e. large integers)
*
* if these bit vector routines are ever supposed to be more
* general, the desired length should be passed in to bitv_alloc()
* instead of defining a maximum here. but knowing the max ahead
* of time allows for simpler code and we know the max that will
* fit into a diagcode. on the minimum side, the below define
* must be at least sizeof (unsigned).
*/
/* data structure used to hold a bit vector */
struct bitv {
unsigned char v[BITV_MAX_BYTES];
};
/* allocate a new, zeroed out bit vector */
static bitv *
bitv_alloc(void)
{
int i;
if (bv)
for (i = 0; i < BITV_MAX_BYTES; i++)
bv->v[i] = 0;
return (bv);
}
/* free a bit vector that was allocated with bitv_alloc() */
static void
{
}
/* shift left a bit vector by a given number of bits. fill with zeros. */
static void
{
while (bits > 0) {
int i;
/* how many bits this iteration? 8 max. */
if (iterbits > 8)
iterbits = 8;
for (i = BITV_MAX_BYTES - 1; i > 0; i--) {
}
}
}
/* force a given number of bits to a specific value */
static void
{
int i = 0;
/* assumption: bits * 8 <= sizeof (val) */
while (bits > 0) {
unsigned mask;
if (iterbits > 8)
iterbits = 8;
/*
* the following can't go off end of bv->v[] since
* BITV_MAX_BYTES is assumed to be at least sizeof
* unsigned and val can't be more than sizeof unsigned
* bytes long.
*/
i++;
}
}
/* given a value and number of bits, shift it in from the right */
static void
{
}
/* given a bit vector and a number of bits, shift it in from the right */
static void
{
/* first handle partial byte shift in */
/* now handle any remaining full byte shift ins */
while (byteindex >= 0)
}
/* return the number of bits required to hold the current bit vector's value */
static int
{
int i;
for (i = BITV_MAX_BYTES - 1; i >= 0; i--)
if (bv->v[i]) {
int bit;
/* this can't happen, so do *something* */
return ((i + 1) * 8);
}
return (0);
}
/* extract chunks of bits from bit vector */
static unsigned
{
unsigned retval = 0;
int bit;
/*
* entry assumptions:
* limbit > lobit
* limbit - lobit <= sizeof (unsigned) * 8
*/
retval <<= 1;
}
return (retval);
}
/*
* multiply by a given value
*
* on overflow, bit vector will hold least significant BITV_MAX_BYTES,
* return value will be -1, and errno will be ERANGE. otherwise
* return is zero and bit vector holds the product.
*/
static int
{
unsigned short result;
unsigned k = 0;
int valbyte;
int bvbyte;
int i;
/* start with a zeroed out bit vector to hold result */
for (i = 0; i < BITV_MAX_BYTES; i++)
prod[i] = 0;
/* from most-significant byte of val to least... */
/* from most significant byte of bv to least */
/*
* we're not storing digits past
* BITV_MAX_BYTES, so if they aren't
* zeros, then signal an overflow.
*/
if (result & 0xff) {
return (-1);
}
} else
/* "carry the 1..." */
k = result >> 8;
}
/* store result in bv */
for (i = 0; i < BITV_MAX_BYTES; i++)
return (0);
}
/*
* add in a given value
*
* on overflow, bit vector will hold least significant BITV_MAX_BYTES,
* return value will be -1, and errno will be ERANGE. otherwise
* return is zero and bit vector holds the sum.
*/
static int
{
unsigned short result;
int i;
for (i = 0; i < BITV_MAX_BYTES; i++) {
if (i < sizeof (val))
else
}
if (cf) {
return (-1);
}
return (0);
}
/*
* subtract out a given value
*
* on underflow, bit vector will hold least significant BITV_MAX_BYTES,
* return value will be -1, and errno will be ERANGE. otherwise
* return is zero and bit vector holds the difference.
*/
static int
{
unsigned short minuend;
unsigned short subtrahend;
int i;
for (i = 0; i < BITV_MAX_BYTES; i++) {
if (i < sizeof (val))
else
subtrahend = bf;
if (subtrahend > minuend) {
bf = 1;
} else
bf = 0;
}
if (bf) {
return (-1);
}
return (0);
}
/*
* see if bv is greater than or equal to a given value
*/
static int
{
unsigned short minuend;
unsigned short subtrahend;
int i;
for (i = 0; i < BITV_MAX_BYTES; i++) {
if (i < sizeof (val))
else
subtrahend = bf;
if (subtrahend > minuend)
bf = 1;
else
bf = 0;
}
return (!bf);
}
static bitv *
{
unsigned long long val;
return (NULL);
}
if (*s == '0') {
s++;
if (*s == 'x') {
s++;
base = 16;
} else
base = 8;
}
while (isxdigit(*s)) {
/* isxdigit() let's in too much, depending on base */
break;
break;
/* convert the digit to binary */
if (isdigit(*s))
val = *s - '0';
else
/*
* multiply our big integer by base,
* add in the most recent digit,
* and check for overflow
*/
return (NULL);
}
s++;
}
return (bv);
}
/* return 0 if two bit vectors represent the same number */
static int
{
int i;
for (i = BITV_MAX_BYTES - 1; i >= 0; i--)
return (-1);
return (1);
return (0);
}
/* CRC code... */
0x00000000,
0x04C11DB7, 0x09823B6E, 0x0D4326D9, 0x130476DC, 0x17C56B6B,
0x1A864DB2, 0x1E475005, 0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6,
0x2B4BCB61, 0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD,
0x4C11DB70, 0x48D0C6C7, 0x4593E01E, 0x4152FDA9, 0x5F15ADAC,
0x5BD4B01B, 0x569796C2, 0x52568B75, 0x6A1936C8, 0x6ED82B7F,
0x639B0DA6, 0x675A1011, 0x791D4014, 0x7DDC5DA3, 0x709F7B7A,
0x745E66CD, 0x9823B6E0, 0x9CE2AB57, 0x91A18D8E, 0x95609039,
0x8B27C03C, 0x8FE6DD8B, 0x82A5FB52, 0x8664E6E5, 0xBE2B5B58,
0xBAEA46EF, 0xB7A96036, 0xB3687D81, 0xAD2F2D84, 0xA9EE3033,
0xA4AD16EA, 0xA06C0B5D, 0xD4326D90, 0xD0F37027, 0xDDB056FE,
0xD9714B49, 0xC7361B4C, 0xC3F706FB, 0xCEB42022, 0xCA753D95,
0xF23A8028, 0xF6FB9D9F, 0xFBB8BB46, 0xFF79A6F1, 0xE13EF6F4,
0xE5FFEB43, 0xE8BCCD9A, 0xEC7DD02D, 0x34867077, 0x30476DC0,
0x3D044B19, 0x39C556AE, 0x278206AB, 0x23431B1C, 0x2E003DC5,
0x2AC12072, 0x128E9DCF, 0x164F8078, 0x1B0CA6A1, 0x1FCDBB16,
0x018AEB13, 0x054BF6A4, 0x0808D07D, 0x0CC9CDCA, 0x7897AB07,
0x7C56B6B0, 0x71159069, 0x75D48DDE, 0x6B93DDDB, 0x6F52C06C,
0x6211E6B5, 0x66D0FB02, 0x5E9F46BF, 0x5A5E5B08, 0x571D7DD1,
0x53DC6066, 0x4D9B3063, 0x495A2DD4, 0x44190B0D, 0x40D816BA,
0xACA5C697, 0xA864DB20, 0xA527FDF9, 0xA1E6E04E, 0xBFA1B04B,
0xBB60ADFC, 0xB6238B25, 0xB2E29692, 0x8AAD2B2F, 0x8E6C3698,
0x832F1041, 0x87EE0DF6, 0x99A95DF3, 0x9D684044, 0x902B669D,
0x94EA7B2A, 0xE0B41DE7, 0xE4750050, 0xE9362689, 0xEDF73B3E,
0xF3B06B3B, 0xF771768C, 0xFA325055, 0xFEF34DE2, 0xC6BCF05F,
0xC27DEDE8, 0xCF3ECB31, 0xCBFFD686, 0xD5B88683, 0xD1799B34,
0xDC3ABDED, 0xD8FBA05A, 0x690CE0EE, 0x6DCDFD59, 0x608EDB80,
0x644FC637, 0x7A089632, 0x7EC98B85, 0x738AAD5C, 0x774BB0EB,
0x4F040D56, 0x4BC510E1, 0x46863638, 0x42472B8F, 0x5C007B8A,
0x58C1663D, 0x558240E4, 0x51435D53, 0x251D3B9E, 0x21DC2629,
0x2C9F00F0, 0x285E1D47, 0x36194D42, 0x32D850F5, 0x3F9B762C,
0x3B5A6B9B, 0x0315D626, 0x07D4CB91, 0x0A97ED48, 0x0E56F0FF,
0x1011A0FA, 0x14D0BD4D, 0x19939B94, 0x1D528623, 0xF12F560E,
0xF5EE4BB9, 0xF8AD6D60, 0xFC6C70D7, 0xE22B20D2, 0xE6EA3D65,
0xEBA91BBC, 0xEF68060B, 0xD727BBB6, 0xD3E6A601, 0xDEA580D8,
0xDA649D6F, 0xC423CD6A, 0xC0E2D0DD, 0xCDA1F604, 0xC960EBB3,
0xBD3E8D7E, 0xB9FF90C9, 0xB4BCB610, 0xB07DABA7, 0xAE3AFBA2,
0xAAFBE615, 0xA7B8C0CC, 0xA379DD7B, 0x9B3660C6, 0x9FF77D71,
0x92B45BA8, 0x9675461F, 0x8832161A, 0x8CF30BAD, 0x81B02D74,
0x857130C3, 0x5D8A9099, 0x594B8D2E, 0x5408ABF7, 0x50C9B640,
0x4E8EE645, 0x4A4FFBF2, 0x470CDD2B, 0x43CDC09C, 0x7B827D21,
0x7F436096, 0x7200464F, 0x76C15BF8, 0x68860BFD, 0x6C47164A,
0x61043093, 0x65C52D24, 0x119B4BE9, 0x155A565E, 0x18197087,
0x1CD86D30, 0x029F3D35, 0x065E2082, 0x0B1D065B, 0x0FDC1BEC,
0x3793A651, 0x3352BBE6, 0x3E119D3F, 0x3AD08088, 0x2497D08D,
0x2056CD3A, 0x2D15EBE3, 0x29D4F654, 0xC5A92679, 0xC1683BCE,
0xCC2B1D17, 0xC8EA00A0, 0xD6AD50A5, 0xD26C4D12, 0xDF2F6BCB,
0xDBEE767C, 0xE3A1CBC1, 0xE760D676, 0xEA23F0AF, 0xEEE2ED18,
0xF0A5BD1D, 0xF464A0AA, 0xF9278673, 0xFDE69BC4, 0x89B8FD09,
0x8D79E0BE, 0x803AC667, 0x84FBDBD0, 0x9ABC8BD5, 0x9E7D9662,
0x933EB0BB, 0x97FFAD0C, 0xAFB010B1, 0xAB710D06, 0xA6322BDF,
0xA2F33668, 0xBCB4666D, 0xB8757BDA, 0xB5365D03, 0xB1F740B4
};
static void
{
}