diff --git a/src/hci/strerror.c b/src/hci/strerror.c index 56b07e8a..045e6357 100644 --- a/src/hci/strerror.c +++ b/src/hci/strerror.c @@ -24,9 +24,60 @@ static struct errortab errortab_end[0] __table_end ( struct errortab, errortab ); /** - * Retrieve string representation of error number. + * Find error description * * @v errno Error number + * @v mask Mask of bits that we care about + * @ret errortab Error description, or NULL + */ +static struct errortab * find_error ( int errno, int mask ) { + struct errortab *errortab; + + for ( errortab = errortab_start ; errortab < errortab_end ; + errortab++ ) { + if ( ( ( errortab->errno ^ errno ) & mask ) == 0 ) + return errortab; + } + + return NULL; +} + +/** + * Find closest error description + * + * @v errno Error number + * @ret errortab Error description, or NULL + * + * + */ +static struct errortab * find_closest_error ( int errno ) { + struct errortab *errortab; + + /* First, look for an exact match */ + if ( ( errortab = find_error ( errno, 0x7fffffff ) ) != NULL ) + return errortab; + + /* Second, try masking off the gPXE-specific bit and seeing if + * we have an entry for the generic POSIX error message. + */ + if ( ( errortab = find_error ( errno, 0x0000ffff ) ) != NULL ) + return errortab; + + /* Lastly, try masking off the POSIX bits and seeing if we + * have a match just based on the PXENV component. This + * allows us to report errors from underlying PXE stacks. + */ + if ( ( errortab = find_error ( ( errno & 0x000000ff ), + 0xffff00ff ) ) != NULL ) + return errortab; + + return NULL; +} + +/** + * Retrieve string representation of error number. + * + * @v errno/rc Error number or return status code * @ret strerror Pointer to error text * * If the error is not found in the linked-in error tables, generates @@ -37,21 +88,25 @@ static struct errortab errortab_end[0] * */ const char * strerror ( int errno ) { - static char *generic_message = "Error 0x0000"; + static char errbuf[64]; struct errortab *errortab; /* Allow for strerror(rc) as well as strerror(errno) */ if ( errno < 0 ) errno = -errno; - for ( errortab = errortab_start ; errortab < errortab_end ; - errortab++ ) { - if ( errortab->errno == errno ) - return errortab->text; + /* Find the error description, if one exists */ + errortab = find_closest_error ( errno ); + + /* Construct the error message */ + if ( errortab ) { + snprintf ( errbuf, sizeof ( errbuf ), "%s (%#08x)", + errortab->text, errno ); + } else { + snprintf ( errbuf, sizeof ( errbuf ), "Error %#08x", errno ); } - sprintf ( generic_message + 8, "%hx", errno ); - return generic_message; + return errbuf; } /** The most common errors */