|
|
1.1 root 1: #define _DDI_DKI 1
2: #define _SYSV4 1
3:
4: /*
5: * Error-reporting code....
6: */
7:
8: /*
9: *-IMPORTS:
10: * <common/ccompat.h>
11: * __PROTO ()
12: * __USE_PROTO__
13: * __ARGS ()
14: * <common/xdebug.h>
15: * __LOCAL__
16: * <sys/inline.h>
17: * splhi ()
18: * splx ()
19: * <sys/ksynch.h>
20: * lock_t
21: * LOCK ()
22: * LOCK_ALLOC ()
23: * UNLOCK ()
24: * <common/_null.h>
25: * NULL
26: * <limits.h>
27: * CHAR_BIT
28: * <stdarg.h>
29: * va_list
30: * va_start ()
31: * va_arg ()
32: * va_end ()
33: *
34: *-PRIVATE DEPENDENCIES:
35: * _put_console ()
36: * _put_putbuf ()
37: */
38:
39: #include <common/ccompat.h>
40: #include <common/xdebug.h>
41: #include <sys/inline.h>
42: #include <sys/ksynch.h>
43: #include <common/_null.h>
44: #include <sys/ddi.h>
45:
46: #include <limits.h>
47: #include <stdarg.h>
48:
49: #include <sys/cmn_err.h>
50:
51: #ifdef __MSDOS__
52:
53: #include <process.h>
54:
55: #endif
56:
57:
58: /*
59: *-GLOBAL VARIABLES:
60: * conlock lock to single-thread console output
61: * putlock lock to single-thread putbuf output
62: */
63:
64: /*
65: * Note that these locks are always acquired in the order conlock -> putlock;
66: * this is required to ensure that the system remains deadlock-free. The
67: * hierarchy mechanism is used to enforce this constraint.
68: *
69: * We use the user namespace for these since if they are actually made public
70: * by definitions in <common/xdebug.h> then they will still not conflict with
71: * user symbols (ie, we assume that this module is an "implementation"
72: * module...
73: */
74:
75: __LOCAL__ lock_t * _conlock;
76: __LOCAL__ lock_t * _putlock;
77:
78:
79: /*
80: * The following are not global variables, they're static constants.
81: */
82:
83: static char * message_level [] = {
84: "",
85: "NOTICE : ",
86: "WARNING : ",
87: "PANIC : ",
88: "<INVALID ERROR LEVEL> : "
89: };
90:
91:
92: /*
93: * The following external function declarations exist for internal layering
94: * purposes and do not appear in any headers. The names begin with a single
95: * underscore (reserved for the user with internal linkage, reserved for the
96: * system with external linkage) so as not to conflict with any user-defined
97: * symbol names.
98: *
99: * If you find this use of the implementation namespace distasteful, then
100: * you'll have to move the function definitions in here.
101: *
102: * Note also that these functions will have the default language linkage
103: * for the translator, ie we allow these functions to be mangled C++. This
104: * constrains them to be produced by the same translator used for this
105: * module.
106: */
107:
108: #if __COHERENT__
109: #define _put_console(c) putchar (c)
110: #else
111: void _put_console __PROTO ((unsigned char _outch));
112: #endif
113:
114: void _put_putbuf __PROTO ((unsigned char _outch));
115:
116:
117: /*
118: *-STATUS:
119: * DDI/DKI
120: *
121: *-NAME:
122: * cmn_err () display an error message or panic the system
123: *
124: *-SYNOPSIS:
125: * #include <sys/cmn_err.h>
126: *
127: * void cmn_err (int level, char * format, ...);
128: *
129: *-ARGUMENTS:
130: * level "level" indicates the severity of the error condition.
131: * Valid levels are:
132: * CE_CONT used to continue a previous message or to
133: * display an informative message not connected
134: * with an error.
135: * CE_NOTE used to display a message preceded with
136: * NOTICE:. This message is used to report system
137: * events that do not necessarily require action,
138: * by may interest the system administrator. For
139: * example, a message saying that a sector on a
140: * disk needs to be accessed repeatedly before it
141: * can be accessed correctly might be noteworthy.
142: * CE_WARN use to display a message preceded with
143: * WARNING:. This message is used to report
144: * system events that require immediate
145: * attention, such as those where if an action is
146: * not taken, the system may panic. For example,
147: * where a peripheral device does not initialize
148: * correctly, this level should be used.
149: * CE_PANIC used to display a message preceded by PANIC:,
150: * and panic the system. Drivers should use this
151: * level only for debugging or in the case of
152: * severe errors that indicate that the system
153: * cannot continue to function. This level halts
154: * processing.
155: *
156: * format The message to be displayed. By default, the message
157: * is sent both to the system console and to the circular
158: * kernel buffer, "putbuf". If the first character in
159: * "format" is an exclamation point ("!"), the message
160: * goes only to "putbuf". If the first character in
161: * "format" is a circumflex ("^"), the message goes only
162: * to the console. The size of the circular buffer
163: * "putbuf" is defined by the kernel variable "putbufsz".
164: * Driver developers or administrators can read the
165: * "putbuf" buffer using appropriate debugging or
166: * administrative tools.
167: *
168: * cmn_err () appends '\n' to each "format" string, even
169: * when a message is sent to "putbuf", except when level
170: * is CE_CONT.
171: *
172: * Valid conversion specifications are %s, %u, %d, %o,
173: * and %x. The cmn_err () function is otherwise similar
174: * to the printf () library subroutine is its
175: * interpretation of the "format" string, except that
176: * cmn_err () does not accept length specifications in
177: * conversion specifications. For example, %3d is invalid
178: * and will be treated as a literal string, resulting in
179: * a mismatch of arguments.
180: *
181: * ... the set of arguments passed with the message being
182: * displayed. Any argument within the range of supported
183: * conversion specifications can be passed.
184: *
185: *-DESCRIPTION:
186: * cmn_err () displays a specified message on the console and/or stores
187: * it in the kernel buffer "putbuf". cmn_err () can also panic the
188: * system.
189: *
190: * At times a driver may encounter error conditions requiring the
191: * attention of a system console monitor. These conditions may mean
192: * halting the system; however, this must be done with caution. Except
193: * during the debugging stage, or in the case of a serious, unrecoverable
194: * error, a driver should never stop the system.
195: *
196: * The cmn_err () function with the CE_CONT argument can be used by
197: * driver developers as a driver code debugging tool. However, using
198: * cmn_err () in this capacity can change system timing characteristics.
199: *
200: *-NOTES:
201: * Does not sleep.
202: *
203: * If "level" is CE_PANIC, then driver defined basic locks, read/write
204: * locks, and sleep locks may not be held across calls to this function.
205: * For other levels, locks may be held.
206: */
207:
208: enum { OUT_CONSOLE = 1,
209: OUT_PUTBUF = 2,
210: OUT_LONG = 4,
211: OUT_SHORT = 8,
212: OUT_SIGNED = 16
213: };
214:
215: typedef char * _string_t; /* for va_arg () */
216: typedef unsigned short _ushort_t;
217: typedef unsigned int _uint_t;
218: typedef unsigned long _ulong_t;
219:
220:
221: #if __USE_PROTO__
222: void (cmn_err) (int level, char * format, ...)
223: #else
224: void
225: cmn_err __ARGS ((level, format))
226: int level;
227: char * format;
228: #endif
229: {
230: /*
231: * The following local data is used for converting numeric data to
232: * strings. Numbuf is defined such that it is large enough to hold
233: * the maximum number of digits that could be generated from any
234: * conversion specification (currently, the longest possible spec is
235: * %lo).
236: */
237:
238: char numbuf [(sizeof (long) * CHAR_BIT + 2) / 3 + 1];
239: char * numptr;
240: int radix;
241: long svalue;
242: unsigned long value;
243:
244: va_list args;
245:
246: unsigned output; /* who to output to */
247:
248: pl_t con_pl; /* for locking */
249: pl_t put_pl;
250:
251:
252: if (format == NULL)
253: format = "<cmn_err: no error message was supplied>";
254:
255: if (* format == '!') {
256: format ++;
257: output = OUT_PUTBUF;
258: } else if (* format == '^') {
259: format ++;
260: output = OUT_CONSOLE;
261: } else
262: output = OUT_PUTBUF | OUT_CONSOLE;
263:
264:
265: /*
266: * Before we generate any output, we should lock the console/putbuf
267: * so that our messages won't get interspersed with diagnostic output
268: * from interrupt handlers or other CPUs.
269: *
270: * If we get called before the locks have been allocated, proceed
271: * at the highest interrupt priority as a fallback.
272: */
273:
274: if (_conlock != NULL) {
275: if ((output & OUT_CONSOLE) != 0)
276: con_pl = LOCK (_conlock, plhi);
277:
278: if ((output & OUT_PUTBUF) != 0)
279: put_pl = LOCK (_putlock, plhi);
280: } else
281: con_pl = splhi ();
282:
283:
284: /*
285: * Check that the level argument is reasonable.
286: */
287:
288: if (level < CE_CONT || level > CE_PANIC)
289: level = CE_INVALID;
290:
291:
292: /*
293: * We should think about generating the date and as accurate a time
294: * reading as possible along with the fixed-text header.
295: *
296: * For now, we'll just generate some fixed text.
297: */
298:
299: numptr = message_level [level];
300:
301: while (* numptr != 0) {
302: if ((output & OUT_CONSOLE) != 0)
303: _put_console (* numptr);
304:
305: if ((output & OUT_PUTBUF) != 0)
306: _put_putbuf (* numptr);
307:
308: numptr ++;
309: }
310:
311:
312: /*
313: * Now start generating formatted output.
314: *
315: * The manual page quoted in the function header doesn't say whether
316: * the 'l' and 'h' modifiers are available for conversion
317: * specifications. We'll implement them anyway.
318: */
319:
320: va_start (args, format);
321:
322: while (* format != 0) {
323: if (format [0] == '%') {
324: /*
325: * Process the conversion-specifications.
326: *
327: * We temporarily borrow 'radix' as a temporary for
328: * working out how long the conversion specification
329: * is.
330: */
331:
332:
333: output &= ~ (OUT_LONG | OUT_SHORT | OUT_SIGNED);
334:
335: radix = 2;
336:
337: if (format [radix - 1] == 'h') {
338: output |= OUT_SHORT;
339: radix ++;
340: } else if (format [radix - 1] == 'l') {
341: output |= OUT_LONG;
342: radix ++;
343: }
344:
345: switch ((format += radix) [-1]) {
346:
347: case 's':
348: numptr = va_arg (args, _string_t);
349: goto out_string;
350:
351: case 'd':
352: /*
353: * This is the only signed numeric conversion
354: * specification, so we process the sign here.
355: */
356:
357: radix = 10;
358:
359: if ((output & OUT_SHORT) != 0)
360: svalue = (short) va_arg (args, int);
361: else if ((output & OUT_LONG) != 0)
362: svalue = va_arg (args, long);
363: else
364: svalue = va_arg (args, int);
365:
366: if (svalue < 0) {
367: if ((output & OUT_CONSOLE) != 0)
368: _put_console ('-');
369:
370: if ((output & OUT_PUTBUF) != 0)
371: _put_putbuf ('-');
372:
373: svalue = - svalue;
374: }
375:
376: output |= OUT_SIGNED;
377: break;
378:
379: case 'o':
380: radix = 8;
381: break;
382:
383: case 'u':
384: radix = 10;
385: break;
386:
387: case 'x':
388: radix = 16;
389: break;
390:
391: case '%':
392: /*
393: * Special case: %% -> %
394: */
395:
396: format -= 1;
397: goto bad_format;
398:
399: default:
400: /*
401: * It's not a valid conversion, so we back
402: * up "format".
403: */
404: format -= radix;
405: goto bad_format;
406: }
407:
408:
409: /*
410: * All numeric conversions come here.
411: */
412:
413: if ((output & OUT_SIGNED) != 0)
414: value = svalue;
415: else if ((output & OUT_SHORT) != 0)
416: value = (_ushort_t) va_arg (args, _uint_t);
417: else if ((output & OUT_LONG) != 0)
418: value = va_arg (args, _ulong_t);
419: else
420: value = va_arg (args, _uint_t);
421:
422:
423: /*
424: * Now we generate the output digits one-at-a-time in
425: * reverse order. We step back from the end of the
426: * conversion buffer so that at the end of the
427: * conversion process we have a C string with the
428: * characters in a 'normal' order.
429: *
430: * (This allows the final output loop to be folded in
431: * with the string-output code).
432: */
433:
434: numptr = & numbuf [sizeof (numbuf) - 1];
435:
436: * numptr = 0; /* terminate the output string */
437:
438: do {
439: int rem = (int) (value % radix);
440: value /= radix;
441:
442: * -- numptr = (rem < 10) ? rem + '0' :
443: rem + 'a' - 10;
444: } while (value > 0);
445:
446:
447: /*
448: * Copy temporary numeric-conversion string or
449: * user-supplied string argument to the output.
450: */
451:
452: out_string:
453: while (* numptr != 0) {
454: if ((output & OUT_CONSOLE) != 0)
455: _put_console (* numptr);
456:
457: if ((output & OUT_PUTBUF) != 0)
458: _put_putbuf (* numptr);
459:
460: numptr ++;
461: }
462: continue;
463: }
464: bad_format:
465: if ((output & OUT_CONSOLE) != 0)
466: _put_console (* format);
467:
468: if ((output & OUT_PUTBUF) != 0)
469: _put_putbuf (* format);
470:
471: format ++;
472: }
473:
474:
475: /*
476: * Output a trailing '\n' unless the level is CE_CONT
477: */
478:
479: if (level != CE_CONT) {
480: if ((output & OUT_CONSOLE) != 0)
481: _put_console ('\n');
482:
483: if ((output & OUT_PUTBUF) != 0)
484: _put_putbuf ('\n');
485: }
486:
487:
488: /*
489: * Now release the locks we acquired, and consider returning to the
490: * caller (unless this is a panic).
491: *
492: * A minor point: if we panic, we should release our locks but
493: * without causing interrupts to be enabled on this CPU; in order to
494: * do this we kludge "con_pl" and "put_pl" to be "plhi";
495: */
496:
497: if (level >= CE_PANIC) /* panic on an invalid level */
498: con_pl = put_pl = plhi;
499:
500:
501: if (_conlock != NULL) {
502: if ((output & OUT_PUTBUF) != 0)
503: UNLOCK (_putlock, put_pl);
504:
505: if ((output & OUT_CONSOLE) != 0)
506: LOCK (_conlock, con_pl);
507: } else
508: (void) splx (con_pl);
509:
510:
511: if (level >= CE_PANIC) {
512: /*
513: * This CPU is shutting down. The actions to be taken here
514: * are so highly system-specific that we'll just throw them
515: * into another file.
516: */
517:
518: #ifdef __MSDOS__
519: splx (plbase);
520:
521: exit (3); /* call atexit () functions */
522: #endif
523: }
524: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.