4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1988 AT&T */
28 /* All Rights Reserved */
30 #pragma ident "%Z%%M% %I% %E% SMI"
36 * fmtmsg() Writes a message in standard format.
37 * addseverity() Adds a severity definition to the list of known
38 * severity definitions.
41 * - None of these functions can use strtok().
45 * Header Files Referenced:
46 * <stdio.h> C Standard I/O Definitions
47 * <string.h> C string handling definitions
48 * <fcntl.h> UNIX file control definitions
49 * <errno.h> UNIX error numbers and definitions
50 * <fmtmsg.h> Global definitions for fmtmsg()
51 * <stdlib.h> miscellaneous function declarations
54 #pragma weak _fmtmsg = fmtmsg
55 #pragma weak _addseverity = addseverity
60 #include <sys/types.h>
73 * External functions referenced:
74 * (Others may be defined in header files above)
76 * getenv Extracts data from the environment
77 * libc_malloc Allocates space from main memory
78 * libc_free Frees space allocated via libc_malloc()
79 * strtol Convert string to "long"
80 * clearerr Clears an error on a stream (this is to make "lint"
86 * Local Constant Definitions
91 * TRUE Boolean value for "true" (any bits on)
92 * FALSE Boolean value for "false" (all bits off)
103 #define MAX_MSG_SIZE 1024
106 * Keywords for fields named in the MSGVERB environment variable.
109 #define ST_LBL "label"
110 #define ST_SEV "severity"
111 #define ST_TXT "text"
113 #define ST_ACT "action"
117 * The following constants define the value of the "msgverb"
118 * variable. This variable tells fmtmsg() which parts of the
119 * standard message it is to display. If !(msgverb&MV_SET),
120 * fmtmsg() will interrogate the "MSGVERB" environment variable
121 * and set "msgverb" accordingly.
123 * NOTE: This means that if MSGVERB changes after the first call
124 * to fmtmsg(), it will be ignored.
127 * MV_INV Check MSGVERB environment variable (invalidates value)
128 * MV_SET MSGVERB checked, msgverb value valid
129 * MV_LBL "label" selected
130 * MV_SEV "severity" selected
131 * MV_TXT "text" selected
132 * MV_TAG "messageID" selected
133 * MV_ACT "action" selected
135 * MV_ALL All components selected
136 * MV_DFLT Default value for MSGVERB
140 #define MV_SET 0x0001
141 #define MV_LBL 0x0002
142 #define MV_SEV 0x0004
143 #define MV_TXT 0x0008
144 #define MV_TAG 0x0010
145 #define MV_ACT 0x0020
147 #define MV_ALL (MV_LBL|MV_SEV|MV_TXT|MV_TAG|MV_ACT)
148 #define MV_DFLT (MV_LBL|MV_SEV|MV_TXT|MV_TAG|MV_ACT)
153 * Strings defining the different severities of a message.
154 * Internationalization may demand that these come from the message database
157 #define SV_UNK "UNKNOWN"
158 #define SV_HALT "HALT"
159 #define SV_ERROR "ERROR"
160 #define SV_WARN "WARNING"
161 #define SV_INF "INFO"
165 * Text string if none is provided:
168 #define DEFLT_TEXT "No text provided with this message"
172 * Text string introduction for "action". This may have to come from
173 * the message database because of internationalization.
176 #define ACTINTRO "TO FIX: "
181 * SEPSTR is the string that separates the "label" from what follows it,
182 * and the severity from what follows it.
190 * Miscellaneous constants:
191 * CONNAME Filesystem entry name for the system console
194 #define CONNAME "/dev/console"
197 * Local data type definitions
201 * Severity string structure
204 * sevvalue Value of the severity-level being defined
205 * sevkywd Keyword identifying the severity
206 * sevprptr Pointer to the string associated with the value
207 * sevnext Pointer to the next value in the list.
210 * sevvalue Must be a non-negative integer (>=0)
212 * There are three (possibly null) lists of these structures.
213 * 1) is the list of standard severities
214 * 2) is the list of severity-levels defined by SEV_LEVEL
215 * 3) is the list of severity-levels defined by calls to
222 const char *sevprstr
;
223 struct sevstr
*sevnext
;
229 * Contains the internal representation or the
230 * MSGVERB environment variable.
231 * sevlook TRUE if fmtmsg() has to look at SEV_LEVEL the
232 * next time it is called.
233 * paugsevs struct sevstr *
234 * Head of the linked list of structures that define
235 * severities that augment the standard severities,
236 * as defined by addseverity().
237 * penvsevs struct sevstrs *
238 * Head of the linked list of structures that define
239 * severities that augment the standard severities,
240 * as defined by SEV_LEVEL.
241 * pstdsevs struct sevstrs *
242 * Head of the linked list of structures that define
243 * the standard severities.
246 static mutex_t fmt_lock
= DEFAULTMUTEX
;
248 static int msgverb
= 0;
249 static int sevlook
= TRUE
;
251 static struct sevstr
*paugsevs
= (struct sevstr
*)NULL
;
252 static struct sevstr
*penvsevs
= (struct sevstr
*)NULL
;
254 static struct sevstr sevstrs
[] = {
255 { MM_HALT
, "", SV_HALT
, &sevstrs
[1]},
256 { MM_ERROR
, "", SV_ERROR
, &sevstrs
[2]},
257 { MM_WARNING
, "", SV_WARN
, &sevstrs
[3]},
258 { MM_INFO
, "", SV_INF
, (struct sevstr
*)NULL
},
260 static struct sevstr
*pstdsevs
= &sevstrs
[0];
263 * static char *exttok(str, delims)
267 * This function examines the string pointed to by "str", looking
268 * for the first occurrence of any of the characters in the string
269 * whose address is "delims". It returns the address of that
270 * character or (char *)NULL if there was nothing to search.
273 * str Address of the string to search
274 * delims Address of the string containing delimiters
277 * Returns the address of the first occurrence of any of the characters
278 * in "delim" in the string "str" (incl '\0'). If there was nothing
279 * to search, the function returns (char *)NULL.
282 * - This function is needed because strtok() can't be used inside a
283 * function. Besides, strtok() is destructive in the string, which
284 * is undesirable in many circumstances.
285 * - This function understands escaped delimiters as non-delimiters.
286 * Delimiters are escaped by preceding them with '\' characters.
287 * The '\' character also must be escaped.
291 exttok(const char *tok
, const char *delims
)
293 char *tokend
; /* Ptr to the end of the token */
294 char *p
, *q
; /* Temp pointers */
298 * 1. Get the starting address(new string or where we
299 * left off). If nothing to search, return(char *)NULL
300 * 2. Find the end of the string
301 * 3. Look for the first unescaped delimiter closest to the
302 * beginning of the string
303 * 4. Remember where we left off
304 * 5. Return a pointer to the delimiter we found
307 /* Begin at the beginning, if any */
308 if (tok
== (char *)NULL
) {
309 return ((char *)NULL
);
312 /* Find end of the token string */
313 tokend
= (char *)tok
+ (ptrdiff_t)strlen(tok
);
315 /* Look for the 1st occurrence of any delimiter */
316 for (p
= (char *)delims
; *p
!= '\0'; p
++) {
317 for (q
= strchr(tok
, (int)*p
);
318 (q
!= 0) && (q
!= tok
) && (*(q
- (ptrdiff_t)1) == '\\');
319 q
= strchr(q
+ (ptrdiff_t)1, (int)*p
))
321 if ((q
!= 0) && (q
< tokend
))
332 * This function squeezes out all of the escaped character sequences
333 * from the string <str>. It returns a pointer to that string.
337 * The string that is to have its escaped characters removed.
340 * This function returns its argument <str> always.
343 * This function potentially modifies the string it is given.
349 char *p
; /* Temp string pointer */
350 char *q
; /* Temp string pointer */
352 /* Look for an escaped character */
354 while (*p
&& (*p
!= '\\')) p
++;
358 * If there was at least one, squeeze them out
359 * Otherwise, don't touch the argument string
364 while (*q
++ = *p
++) {
370 /* Finished. Return our argument */
375 * struct sevstr *getauxsevs(ptr)
377 * Parses a string that is in the format of the severity definitions.
378 * Returns a pointer to a (malloc'd) structure that contains the
379 * definition, or (struct sevstr *)NULL if none was parsed.
383 * References the string from which data is to be extracted.
384 * If (char *)NULL, continue where we left off. Otherwise,
385 * start with the string referenced by ptr.
387 * Returns: struct sevstr *
388 * A pointer to a malloc'd structure containing the severity definition
389 * parsed from string, or (struct sevstr *)NULL if none.
392 * - This function is destructive to the string referenced by its argument.
396 static char *leftoff
= (char *)NULL
;
398 static struct sevstr
*
399 getauxsevs(char *ptr
)
401 char *current
; /* Ptr to current sev def'n */
402 char *tokend
; /* Ptr to end of current sev def'n */
403 char *kywd
; /* Ptr to extracted kywd */
404 char *valstr
; /* Ptr to extracted sev value */
405 char *prstr
; /* Ptr to extracted print str */
406 char *p
; /* Temp pointer */
407 int val
; /* Converted severity value */
408 int done
; /* Flag, sev def'n found and ok? */
409 struct sevstr
*rtnval
; /* Value to return */
412 /* Start anew or start where we left off? */
413 current
= (ptr
== (char *)NULL
) ? leftoff
: ptr
;
416 /* If nothing to parse, return (char *)NULL */
417 if (current
== (char *)NULL
) {
418 return ((struct sevstr
*)NULL
);
423 * Look through the string "current" for a token of the form
424 * <kywd>,<sev>,<printstring> delimited by ':' or '\0'
427 /* Loop initializations */
429 rtnval
= (struct sevstr
*)NULL
;
431 /* Eat leading junk */
432 while (*(tokend
= exttok(current
, ":,")) == ':') {
433 current
= tokend
+ (ptrdiff_t)1;
436 /* If we've found a <kywd>,... */
437 if (*tokend
== ',') {
441 /* Look for <kywd>,<sev>,... */
442 current
= tokend
+ (ptrdiff_t)1;
443 if (*(tokend
= exttok(current
, ":,")) == ',') {
447 current
= tokend
+ (ptrdiff_t)1;
450 /* Make sure <sev> > 4 */
451 val
= (int)strtol(noesc(valstr
), &p
, 0);
452 if ((val
> 4) && (p
== tokend
)) {
455 * Found <kywd>,<sev>,<printstring>.
456 * remember where we left off
460 exttok(current
, ":")) == ':') {
465 leftoff
= (char *)NULL
;
469 * Alloc structure to contain
470 * severity definition
472 rtnval
= libc_malloc(
473 sizeof (struct sevstr
));
474 if (rtnval
!= NULL
) {
476 /* Fill in structure */
477 rtnval
->sevkywd
= noesc(kywd
);
478 rtnval
->sevvalue
= val
;
479 rtnval
->sevprstr
= noesc(prstr
);
481 (struct sevstr
*)NULL
;
486 * Invalid severity value,
487 * eat thru end of token
490 if (*(tokend
= exttok(prstr
, ":")) ==
497 * Invalid severity definition,
498 * eat thru end of token
505 /* End of string found */
507 leftoff
= (char *)NULL
;
509 } /* while (!done) */
518 * Parces the argument of the MSGVERB environment variable and places
519 * a representation of the value of that value in "msgverb"
532 char *opts
; /* Pointer to MSGVERB's value */
533 char *alloced
; /* Pointer to MSGVERB's value */
534 char *tok
; /* Pointer to current token */
535 char *tokend
; /* Pointer to end of current token */
536 char *nexttok
; /* Pointer to next token */
539 /* Rid ourselves of junk in "msgverb" */
542 /* Get the value of MSGVERB. If none, use default value */
543 if ((opts
= getenv(MSGVERB
)) == (char *)NULL
) {
545 } else { /* MSGVERB has a value. Interpret it */
546 if ((alloced
= libc_malloc(strlen(opts
) + 1)) == NULL
) {
549 /* Make a copy of the value of MSGVERB */
550 nexttok
= strcpy(alloced
, opts
);
552 /* Parse the options given by the user */
553 while ((tok
= nexttok
) != (char *)NULL
) {
555 * Find end of the next token and squeeze
556 * out escaped characters
558 tokend
= exttok(tok
, ":");
561 /* Delimit token and mark next, if any */
562 if (*tokend
== ':') {
563 nexttok
= tokend
+ (ptrdiff_t)1;
566 nexttok
= (char *)NULL
;
569 /* Check for "text" */
570 if (strcmp(tok
, ST_TXT
) == 0) {
573 /* Check for "label" */
574 } else if (strcmp(tok
, ST_LBL
) == 0) {
577 /* Check for "action */
578 } else if (strcmp(tok
, ST_ACT
) == 0) {
581 /* Check for "severity" */
582 } else if (strcmp(tok
, ST_SEV
) == 0) {
585 /* Check for "tag" */
586 } else if (strcmp(tok
, ST_TAG
) == 0) {
589 /* Unknown, ignore MSGVERB value */
592 nexttok
= (char *)NULL
;
597 * Use default if no keywords on MSGVERB
598 * environment variable
603 /* Free allocated space */
614 * This function builds a structure containing auxillary severity
622 static char *sevspace
= (char *)NULL
;
627 struct sevstr
*plast
;
632 /* Look for SEV_LEVEL definition */
633 if ((value
= getenv(SEV_LEVEL
)) != (char *)NULL
) {
635 /* Allocate space and make a copy of the value of SEV_LEVEL */
636 if ((sevspace
= libc_malloc(strlen(value
) + 1)) != NULL
) {
637 (void) strcpy(sevspace
, value
);
639 /* Continue for all severity descriptions */
640 psev
= getauxsevs(sevspace
);
641 plast
= (struct sevstr
*)NULL
;
642 if (psev
!= (struct sevstr
*)NULL
) {
645 while (psev
= getauxsevs((char *)NULL
)) {
646 plast
->sevnext
= psev
;
650 } /* if sevspace != (char *)NULL */
651 } /* if value != (char *)NULL */
655 * int addseverity(value, string)
656 * int value Value of the severity
657 * const char *string Print-string for the severity
661 * The integer value of the severity being added
663 * A pointer to the character-string to be printed
664 * whenever a severity of "value" is printed
667 * Zero if successful, -1 if failed. The function can fail under
668 * the following circumstances:
669 * - libc_malloc() fails
670 * - The "value" is one of the reserved values.
672 * This function permits C applications to define severity-levels
673 * that augment the standard levels and those defined by the
674 * SEV_LEVEL environment variable.
678 addseverity(int value
, const char *string
)
680 struct sevstr
*p
; /* Temp ptr to severity structs */
681 struct sevstr
*q
; /* Temp ptr(follower) to severity */
682 int found
; /* FLAG, element found in the list */
683 int rtnval
; /* Value to return to the caller */
685 /* Make sure we're not trying to redefine one of the reserved values */
691 lmutex_lock(&fmt_lock
);
693 /* Make sure we've interpreted SEV_LEVEL */
702 * Leaf through the list. We may be redefining or removing a
705 q
= (struct sevstr
*)NULL
;
707 for (p
= paugsevs
; !found
&& (p
!= (struct sevstr
*)NULL
);
709 if (p
->sevvalue
== value
) {
710 /* We've a match. Remove or modify the entry */
711 if (string
== (char *)NULL
) {
712 if (q
== (struct sevstr
*)NULL
) {
713 paugsevs
= p
->sevnext
;
715 q
->sevnext
= p
->sevnext
;
719 p
->sevprstr
= string
;
726 /* Adding a definition */
727 if (!found
&& (string
!= (char *)NULL
)) {
728 /* Allocate space for the severity structure */
729 if ((p
= libc_malloc(sizeof (struct sevstr
))) == NULL
) {
730 lmutex_unlock(&fmt_lock
);
735 * Fill in the new structure with the data supplied and add to
736 * the head of the augmented severity list.
739 p
->sevkywd
= (char *)NULL
;
740 p
->sevprstr
= string
;
742 p
->sevnext
= paugsevs
;
745 /* Successfully added a new severity */
747 } else if (string
== (char *)NULL
) {
748 /* Attempting to undefined a non-defined severity */
752 /* Successfully redefined a severity */
755 /* Finished, successful */
756 lmutex_unlock(&fmt_lock
);
761 * Utility function for converting an integer to a string, avoiding stdio.
766 char buf
[12]; /* 32 bits fits in 10 decimal digits */
768 uint_t un
= (n
< 0)? -n
: n
;
771 *cp
++ = "0123456789"[un
% 10];
786 * void writemsg(buf, size, verbosity, label, severity, text, action, tag)
789 * char *buf The buffer in which to format the message
790 * size_t size The size of the buffer
791 * int verbosity A bit-string that indicates which components
793 * const char *label The address of the label-component
794 * int severity The severity value of the message
795 * const char *text The address of the text-component
796 * const char *action The address of the action-component
797 * const char *tag The address of the tag-component
799 * This function formats the message consisting of the label-component,
800 * severity-component, text-component, action-component, and tag-
801 * component into the provided buffer. The "verbosity" argument
802 * tells which components can be selected. Any or all of the
803 * components can be their null-values.
811 writemsg(char *buf
, size_t size
,
812 int verbosity
, const char *label
, int severity
,
813 const char *text
, const char *action
, const char *tag
)
815 struct sevstr
*psev
; /* Ptr for severity str list */
816 char *p
; /* General purpose pointer */
817 char *sevpstr
= NULL
; /* Pointer to severity string */
818 int l1indent
; /* # chars to indent line 1 */
819 int l2indent
; /* # chars to indent line 2 */
820 int textindent
; /* # spaces to indent text */
821 int actindent
= 0; /* # spaces to indent action */
822 int i
; /* General purpose counter */
823 int dolabel
; /* TRUE if label to be written */
824 int dotext
; /* TRUE if text to be written */
825 int dosev
; /* TRUE if severity to be written */
826 int doaction
; /* TRUE if action to be written */
827 int dotag
; /* TRUE if tag to be written */
828 char c
; /* Temp, multiuse character */
829 char sevpstrbuf
[15]; /* Space for SV=%d */
831 char lcllbl
[MM_MXLABELLN
+1]; /* Space for (possibly */
832 /* truncated) label */
833 char lcltag
[MM_MXTAGLN
+1]; /* Space for (possibly */
835 char *ebuf
= buf
+ size
- 2;
838 * initialize variables.
840 sevpstrbuf
[0] = (char)0;
845 * Figure out what fields are to be written (all are optional)
848 dolabel
= (verbosity
& MV_LBL
) && (label
!= MM_NULLLBL
);
849 dosev
= (verbosity
& MV_SEV
) && (severity
!= MM_NULLSEV
);
850 dotext
= (verbosity
& MV_TXT
) && (text
!= MM_NULLTXT
);
851 doaction
= (verbosity
& MV_ACT
) && (action
!= MM_NULLACT
);
852 dotag
= (verbosity
& MV_TAG
) && (tag
!= MM_NULLTAG
);
855 * Figure out how much we'll need to indent the text of the message
858 /* Count the label of the message, if requested */
861 (void) strncpy(lcllbl
, label
, (size_t)MM_MXLABELLN
);
862 lcllbl
[MM_MXLABELLN
] = '\0';
863 textindent
= (int)strlen(lcllbl
) + SEPSTRLN
;
867 * If severity req'd, determine the severity string and factor
868 * into indent count. Severity string generated by:
869 * 1. Search the standard list of severities.
870 * 2. Search the severities added by the application.
871 * 3. Search the severities added by the environment.
872 * 4. Use the default (SV=n where n is the value of the severity).
876 /* Search the default severity definitions */
878 while (psev
!= (struct sevstr
*)NULL
) {
879 if (psev
->sevvalue
== severity
)
881 psev
= psev
->sevnext
;
884 if (psev
== (struct sevstr
*)NULL
) {
886 * Search the severity definitions
887 * added by the application
890 while (psev
!= (struct sevstr
*)NULL
) {
891 if (psev
->sevvalue
== severity
)
893 psev
= psev
->sevnext
;
895 if (psev
== (struct sevstr
*)NULL
) {
897 * Search the severity definitions
898 * added by the environment
901 while (psev
!= (struct sevstr
*)NULL
) {
902 if (psev
->sevvalue
== severity
)
904 psev
= psev
->sevnext
;
906 if (psev
== (struct sevstr
*)NULL
) {
907 /* Use default string, SV=severity */
908 (void) strcpy(sevpstrbuf
, "SV=");
909 itoa(severity
, &sevpstrbuf
[3]);
910 sevpstr
= sevpstrbuf
;
912 sevpstr
= (char *)psev
->sevprstr
;
915 sevpstr
= (char *)psev
->sevprstr
;
918 sevpstr
= (char *)psev
->sevprstr
;
920 /* Factor into indent counts */
921 textindent
+= (int)strlen(sevpstr
) + SEPSTRLN
;
925 * Figure out the indents.
928 if (doaction
&& dotext
) {
929 if (textindent
> ACTINTROLN
) {
931 l2indent
= textindent
- ACTINTROLN
;
932 actindent
= textindent
;
935 actindent
= ACTINTROLN
;
936 if (dosev
|| dolabel
) {
937 l1indent
= ACTINTROLN
- textindent
;
938 textindent
= ACTINTROLN
;
948 actindent
= textindent
+ ACTINTROLN
;
958 /* Write the LABEL, if requested */
960 /* Write spaces to align on the ':' char, if needed */
961 while (--l1indent
>= 0 && buf
< ebuf
)
964 /* Write the label */
965 buf
+= strlcpy(buf
, lcllbl
, ebuf
- buf
);
968 * Write the separator string
969 * (if another component is to follow)
971 if (dosev
|| dotext
|| doaction
|| dotag
)
972 buf
+= strlcpy(buf
, SEPSTR
, ebuf
- buf
);
975 /* Write the SEVERITY, if requested */
977 /* Write spaces to align on the ':' char, if needed */
978 while (--l1indent
>= 0 && buf
< ebuf
)
981 /* Write the severity print-string */
982 buf
+= strlcpy(buf
, sevpstr
, ebuf
- buf
);
985 * Write the separator string
986 * (if another component is to follow)
988 if (dotext
|| doaction
|| dotag
)
989 buf
+= strlcpy(buf
, SEPSTR
, ebuf
- buf
);
992 /* Write the TEXT, if requested */
995 for (c
= *p
++; c
!= NULL
&& buf
< ebuf
; c
= *p
++) {
998 for (i
= 0; i
< textindent
&& buf
< ebuf
; i
++)
1005 * Write ACTION if requested.
1009 if (dotext
&& buf
< ebuf
) {
1011 while (--l2indent
>= 0 && buf
< ebuf
)
1015 /* Write the action-string's introduction */
1016 buf
+= strlcpy(buf
, ACTINTRO
, ebuf
- buf
);
1018 /* Write the "action" string */
1020 for (c
= *p
++; c
!= NULL
&& buf
< ebuf
; c
= *p
++) {
1023 for (i
= 0; i
< actindent
&& buf
< ebuf
; i
++)
1030 * Write the TAG if requested
1035 buf
+= strlcpy(buf
, " ", ebuf
- buf
);
1036 else if (dotext
&& buf
< ebuf
)
1038 (void) strncpy(lcltag
, tag
, (size_t)MM_MXTAGLN
);
1039 lcltag
[MM_MXTAGLN
] = '\0';
1040 buf
+= strlcpy(buf
, lcltag
, ebuf
- buf
);
1044 * Write terminating newline and null byte.
1045 * We reserved space for these at the start.
1052 * int fmtmsg(class, label, severity, text, action, tag)
1057 * const char *action
1060 * If requested, the fmtmsg() function writes a message to the standard
1061 * error stream in the standard message format. Also if requested, it
1062 * will write a message to the system console.
1065 * class Fields which classify the message for the system
1067 * label A character-string that is printed as the "label"
1068 * of the message. Typically identifies the source
1070 * severity Identifies the severity of the message. Either one
1071 * of the standard severities, or possibly one of the
1072 * augmented severities
1073 * text Pointer to the text of the message
1074 * action Pointer to a char string that describes some type
1075 * of corrective action.
1076 * tag A character-string that is printed as the "tag" or
1077 * the message. Typically a pointer to documentation
1080 * -1 if nothing was generated, 0 if everything requested was
1081 * generated, or flags if partially generated.
1084 * - Nothing special for 4.0.
1088 fmtmsg(long class, const char *label
, int severity
,
1089 const char *text
, const char *action
, const char *tag
)
1091 int rtnval
; /* Value to return */
1092 FILE *console
; /* Ptr to "console" stream */
1097 * Determine the "verbosity" of the message. If "msgverb" is
1098 * already set, don't interrogate the "MSGVERB" environment vbl.
1099 * If so, interrogate "MSGVERB" and do initialization stuff also.
1102 lmutex_lock(&fmt_lock
);
1104 if (!(msgverb
& MV_SET
)) {
1111 * Extract the severity definitions from the SEV_LEVEL
1112 * environment variable and save away for later.
1121 /* Set up the default text component [if text==(char *)NULL] */
1122 if (text
== (char *)NULL
)
1125 /* Prepare the message for stderr if requested */
1126 if (class & MM_PRINT
) {
1127 message1
= alloca(MAX_MSG_SIZE
);
1128 writemsg(message1
, MAX_MSG_SIZE
,
1129 msgverb
, label
, severity
, text
, action
, tag
);
1132 /* Prepare the message for the console if requested */
1133 if (class & MM_CONSOLE
) {
1134 message2
= alloca(MAX_MSG_SIZE
);
1135 writemsg(message2
, MAX_MSG_SIZE
,
1136 MV_ALL
, label
, severity
, text
, action
, tag
);
1139 lmutex_unlock(&fmt_lock
);
1143 /* Write the message to stderr if requested */
1144 if (class & MM_PRINT
) {
1146 (void) fputs(message1
, stderr
);
1151 /* Write the message to the console if requested */
1152 if (class & MM_CONSOLE
) {
1153 if ((console
= fopen(CONNAME
, "wF")) != NULL
) {
1155 (void) fputs(message2
, console
);
1156 if (ferror(console
))
1158 (void) fclose(console
);
1164 if ((rtnval
& (MM_NOCON
| MM_NOMSG
)) == (MM_NOCON
| MM_NOMSG
))