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