marc@mercutio.ultra.com (Marc Kwiatkowski {Host Software-AIX}) (05/24/91)
Can anyone recommend a good way to do the above? I am writing an AIXv3 device driver and would like to write error messages and debug messages to the standard error device, using the kernel routine errsave(). I wanted to use a front end to errsave() to build an appropriate error record. This required using vsprintf() in order to accept and then pass on a variable argument list. I had in mind something like the following: #include <varargs.h> #include <sys/err_rec.h> #define ERR_ID (1) #define ERR_NAME "dd" #define ERR_FMT "dd error:" static char *err_msg_ptr = (char *)0; static int err_msg_len = 0; void dd_err_log(format, va_alist) va_dcl /* * This function logs errors to the * standard error-log device. * * Parameters * ========== * char *format * printf format string. * * varargs * Additional printf parameters. * * Returns * ======= * void */ { va_list ap; ERR_REC(ERR_REC_MAX) err_rec; int cnt; va_start(ap); /* * If first time through, set-up static fields * in error record. */ if(err_msg_ptr == (char *)0) { err_rec.error_id = DD_ERR_ID; bcopy(DD_ERR_NAME, err_rec.resource_name, ERR_NAMESIZE); err_msg_ptr = &err_rec.detail_data[0]; /* * Stick the dd_error prefix into the error * message formatted string. */ cnt = sprintf(err_msg_ptr, "%s", DD_ERR_FMT); err_msg_ptr += cnt; /* * Record the amount of the error message formatted * string that is available. */ err_msg_len = ERR_REC_MAX - cnt; } cnt = vsprintf(err_msg, format, ap); /* * If we got an error message larger than can fit * in an error record, then who knows what damage was * done by the above vsprintf. panic, while we still can. */ if(cnt > err_msg_len) { panic("dd_err_log: error message too long to log:\n\t<%s>\n", format); } /* * Log message with error devices. */ errsave(&err_rec, ERR_REC_SIZE + ERR_REC_MAX); va_end(ap); return; } I just discovered, much to my chagrin, that vsprintf is not supported in the kernel. Linking in libc.a causes all the kernel extensions that I do want to be replaced by the libc.a versions, and, as far as I can tell, there is no way to extract just vsprintf.o from libc.a. Even if there were, I'm not sure it would be suitable for use in the kernel. So, I'm prevented from writing an error-log front-end that can gracefully handle variable arguments. I'm also prevented from doing in-line macros for sprintf, because the xlc cpp doesn't support variable argument macros either. Two obvious, but incredibly obnoxious solutions are to either, A, parse the format string myself, or B, write a separate macro for each possible number of printf-style parameter lists. I find it hard to believe that this is how other device-driver and extension writers handle this problem. I'd like to hear other solutions if any. If the solution is simply to use printf, then what is the point of errsave and the error device? I've noticed that AIXv3 seems to have a number of deficiencies of this sort. System requirements strongly suggest you program a certain way, but when you attempt to do so, you find things aren't really set up to let you follow the prescribed method. In addition to the above example I've also noticed the following: The recommend VPD format includes a CRC checksum field. If the conscientious programmer wants to stick to the recommended VPD format, s/he must write her/his own CRC calculation routine, since one was not provided as a basic kernel extension. This does not significantly increase the programmer's work, but it does mean that each driver will have a redundant piece of code, including a 256 byte look-up table. I think the failure to realize this was a glaring oversight. Similarly, the kernel memory allocator, xmalloc, requires an alignment parameter. Rather than specifying alignment as a power of 2, it requires the exponent. That is, instead of 1024, one specifies an alignment of 10. This format is somewhat peculiar, but would be completely acceptable if an integer log2 function were provided, so that I could write xmalloc(n*PAGESIZE, log2(PAGESIZE), pinned_heap). Again, it is no big deal to write a loop shift to calculate the log, but again, this is something every driver writer will have to do, adding unnecessary bloat to the kernel. Well, glad I got that off my chest. I suppose I should submit these as a DCR to IBM. -- Marc P. Kwiatkowski Ultra Network Technologies Internet: marc@ultra.com 101 Daggett Drive uucp: ...!ames!ultra!marc San Jose, CA 95134 USA telephone: 408 922 0100 x249
tif@doorstop.austin.ibm.com (Paul Chamberlain) (05/30/91)
marc@mercutio.ultra.com (Marc Kwiatkowski {Host Software-AIX}) writes: [a bunch of things I'm not able to answer] > If the conscientious programmer wants to stick to the > recommended VPD format, s/he must write her/his own > CRC calculation routine, since one was not provided > as a basic kernel extension. I can't argue with the other stuff, but there is a CRC routine included as a sample in /usr/lpp/bos/samples/ciodd.c. Paul Chamberlain | I do NOT speak for IBM. IBM VNET: PAULCC AT AUSTIN 512/838-9748 | ...!cs.utexas.edu!ibmchs!auschs!doorstop.austin.ibm.com!tif