/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ #pragma ident "%Z%%M% %I% %E% SMI" /* * fmtmsg.c * * Contains: * fmtmsg() Writes a message in standard format. * addseverity() Adds a severity definition to the list of known * severity definitions. * * Notes: * - None of these functions can use strtok(). */ /* * Header Files Referenced: * C Standard I/O Definitions * C string handling definitions * UNIX file control definitions * UNIX error numbers and definitions * Global definitions for fmtmsg() * miscellaneous function declarations */ #pragma weak _fmtmsg = fmtmsg #pragma weak _addseverity = addseverity #include "lint.h" #include "mtlib.h" #include "libc.h" #include #include #include #include #include #include #include #include #include #include #include /* * External functions referenced: * (Others may be defined in header files above) * * getenv Extracts data from the environment * libc_malloc Allocates space from main memory * libc_free Frees space allocated via libc_malloc() * strtol Convert string to "long" * clearerr Clears an error on a stream (this is to make "lint" * happy) */ /* * Local Constant Definitions */ /* * Boolean constants * TRUE Boolean value for "true" (any bits on) * FALSE Boolean value for "false" (all bits off) */ #ifndef FALSE #define FALSE (0) #endif #ifndef TRUE #define TRUE (1) #endif #define MAX_MSG_SIZE 1024 /* * Keywords for fields named in the MSGVERB environment variable. */ #define ST_LBL "label" #define ST_SEV "severity" #define ST_TXT "text" #define ST_TAG "tag" #define ST_ACT "action" /* * The following constants define the value of the "msgverb" * variable. This variable tells fmtmsg() which parts of the * standard message it is to display. If !(msgverb&MV_SET), * fmtmsg() will interrogate the "MSGVERB" environment variable * and set "msgverb" accordingly. * * NOTE: This means that if MSGVERB changes after the first call * to fmtmsg(), it will be ignored. * * Constants: * MV_INV Check MSGVERB environment variable (invalidates value) * MV_SET MSGVERB checked, msgverb value valid * MV_LBL "label" selected * MV_SEV "severity" selected * MV_TXT "text" selected * MV_TAG "messageID" selected * MV_ACT "action" selected * * MV_ALL All components selected * MV_DFLT Default value for MSGVERB */ #define MV_INV 0 #define MV_SET 0x0001 #define MV_LBL 0x0002 #define MV_SEV 0x0004 #define MV_TXT 0x0008 #define MV_TAG 0x0010 #define MV_ACT 0x0020 #define MV_ALL (MV_LBL|MV_SEV|MV_TXT|MV_TAG|MV_ACT) #define MV_DFLT (MV_LBL|MV_SEV|MV_TXT|MV_TAG|MV_ACT) /* * Strings defining the different severities of a message. * Internationalization may demand that these come from the message database */ #define SV_UNK "UNKNOWN" #define SV_HALT "HALT" #define SV_ERROR "ERROR" #define SV_WARN "WARNING" #define SV_INF "INFO" /* * Text string if none is provided: */ #define DEFLT_TEXT "No text provided with this message" /* * Text string introduction for "action". This may have to come from * the message database because of internationalization. */ #define ACTINTRO "TO FIX: " #define ACTINTROLN 8 /* * SEPSTR is the string that separates the "label" from what follows it, * and the severity from what follows it. */ #define SEPSTR ": " #define SEPSTRLN 2 /* * Miscellaneous constants: * CONNAME Filesystem entry name for the system console */ #define CONNAME "/dev/console" /* * Local data type definitions */ /* * Severity string structure * * struct sevstr * sevvalue Value of the severity-level being defined * sevkywd Keyword identifying the severity * sevprptr Pointer to the string associated with the value * sevnext Pointer to the next value in the list. * * Restrictions: * sevvalue Must be a non-negative integer (>=0) * * There are three (possibly null) lists of these structures. * 1) is the list of standard severities * 2) is the list of severity-levels defined by SEV_LEVEL * 3) is the list of severity-levels defined by calls to * addseverity() */ struct sevstr { int sevvalue; const char *sevkywd; const char *sevprstr; struct sevstr *sevnext; }; /* * Local Static Data * msgverb int * Contains the internal representation or the * MSGVERB environment variable. * sevlook TRUE if fmtmsg() has to look at SEV_LEVEL the * next time it is called. * paugsevs struct sevstr * * Head of the linked list of structures that define * severities that augment the standard severities, * as defined by addseverity(). * penvsevs struct sevstrs * * Head of the linked list of structures that define * severities that augment the standard severities, * as defined by SEV_LEVEL. * pstdsevs struct sevstrs * * Head of the linked list of structures that define * the standard severities. */ static mutex_t fmt_lock = DEFAULTMUTEX; static int msgverb = 0; static int sevlook = TRUE; static struct sevstr *paugsevs = (struct sevstr *)NULL; static struct sevstr *penvsevs = (struct sevstr *)NULL; static struct sevstr sevstrs[] = { { MM_HALT, "", SV_HALT, &sevstrs[1]}, { MM_ERROR, "", SV_ERROR, &sevstrs[2]}, { MM_WARNING, "", SV_WARN, &sevstrs[3]}, { MM_INFO, "", SV_INF, (struct sevstr *)NULL}, }; static struct sevstr *pstdsevs = &sevstrs[0]; /* * static char *exttok(str, delims) * const char *str * const char *delims * * This function examines the string pointed to by "str", looking * for the first occurrence of any of the characters in the string * whose address is "delims". It returns the address of that * character or (char *)NULL if there was nothing to search. * * Arguments: * str Address of the string to search * delims Address of the string containing delimiters * * Returns: char * * Returns the address of the first occurrence of any of the characters * in "delim" in the string "str" (incl '\0'). If there was nothing * to search, the function returns (char *)NULL. * * Notes: * - This function is needed because strtok() can't be used inside a * function. Besides, strtok() is destructive in the string, which * is undesirable in many circumstances. * - This function understands escaped delimiters as non-delimiters. * Delimiters are escaped by preceding them with '\' characters. * The '\' character also must be escaped. */ static char * exttok(const char *tok, const char *delims) { char *tokend; /* Ptr to the end of the token */ char *p, *q; /* Temp pointers */ /* * Algorithm: * 1. Get the starting address(new string or where we * left off). If nothing to search, return(char *)NULL * 2. Find the end of the string * 3. Look for the first unescaped delimiter closest to the * beginning of the string * 4. Remember where we left off * 5. Return a pointer to the delimiter we found */ /* Begin at the beginning, if any */ if (tok == (char *)NULL) { return ((char *)NULL); } /* Find end of the token string */ tokend = (char *)tok + (ptrdiff_t)strlen(tok); /* Look for the 1st occurrence of any delimiter */ for (p = (char *)delims; *p != '\0'; p++) { for (q = strchr(tok, (int)*p); (q != 0) && (q != tok) && (*(q - (ptrdiff_t)1) == '\\'); q = strchr(q + (ptrdiff_t)1, (int)*p)) ; if ((q != 0) && (q < tokend)) tokend = q; } /* Done */ return (tokend); } /* * char *noesc(str) * * This function squeezes out all of the escaped character sequences * from the string . It returns a pointer to that string. * * Arguments: * str char * * The string that is to have its escaped characters removed. * * Returns: char * * This function returns its argument always. * * Notes: * This function potentially modifies the string it is given. */ static char * noesc(char *str) { char *p; /* Temp string pointer */ char *q; /* Temp string pointer */ /* Look for an escaped character */ p = str; while (*p && (*p != '\\')) p++; /* * If there was at least one, squeeze them out * Otherwise, don't touch the argument string */ if (*p) { q = p++; while (*q++ = *p++) { if (*p == '\\') p++; } } /* Finished. Return our argument */ return (str); } /* * struct sevstr *getauxsevs(ptr) * * Parses a string that is in the format of the severity definitions. * Returns a pointer to a (malloc'd) structure that contains the * definition, or (struct sevstr *)NULL if none was parsed. * * Arguments: * ptr char * * References the string from which data is to be extracted. * If (char *)NULL, continue where we left off. Otherwise, * start with the string referenced by ptr. * * Returns: struct sevstr * * A pointer to a malloc'd structure containing the severity definition * parsed from string, or (struct sevstr *)NULL if none. * * Notes: * - This function is destructive to the string referenced by its argument. */ /* Static data */ static char *leftoff = (char *)NULL; static struct sevstr * getauxsevs(char *ptr) { char *current; /* Ptr to current sev def'n */ char *tokend; /* Ptr to end of current sev def'n */ char *kywd; /* Ptr to extracted kywd */ char *valstr; /* Ptr to extracted sev value */ char *prstr; /* Ptr to extracted print str */ char *p; /* Temp pointer */ int val; /* Converted severity value */ int done; /* Flag, sev def'n found and ok? */ struct sevstr *rtnval; /* Value to return */ /* Start anew or start where we left off? */ current = (ptr == (char *)NULL) ? leftoff : ptr; /* If nothing to parse, return (char *)NULL */ if (current == (char *)NULL) { return ((struct sevstr *)NULL); } /* * Look through the string "current" for a token of the form * ,, delimited by ':' or '\0' */ /* Loop initializations */ done = FALSE; rtnval = (struct sevstr *)NULL; while (!done) { /* Eat leading junk */ while (*(tokend = exttok(current, ":,")) == ':') { current = tokend + (ptrdiff_t)1; } /* If we've found a ,... */ if (*tokend == ',') { kywd = current; *tokend = '\0'; /* Look for ,,... */ current = tokend + (ptrdiff_t)1; if (*(tokend = exttok(current, ":,")) == ',') { valstr = current; *tokend = '\0'; current = tokend + (ptrdiff_t)1; prstr = current; /* Make sure > 4 */ val = (int)strtol(noesc(valstr), &p, 0); if ((val > 4) && (p == tokend)) { /* * Found ,,. * remember where we left off */ if (*(tokend = exttok(current, ":")) == ':') { *tokend = '\0'; leftoff = tokend + (ptrdiff_t)1; } else { leftoff = (char *)NULL; } /* * Alloc structure to contain * severity definition */ rtnval = libc_malloc( sizeof (struct sevstr)); if (rtnval != NULL) { /* Fill in structure */ rtnval->sevkywd = noesc(kywd); rtnval->sevvalue = val; rtnval->sevprstr = noesc(prstr); rtnval->sevnext = (struct sevstr *)NULL; } done = TRUE; } else { /* * Invalid severity value, * eat thru end of token */ current = tokend; if (*(tokend = exttok(prstr, ":")) == ':') { current++; } } } else { /* * Invalid severity definition, * eat thru end of token */ current = tokend; if (*tokend == ':') current++; } } else { /* End of string found */ done = TRUE; leftoff = (char *)NULL; } } /* while (!done) */ /* Finished */ return (rtnval); } /* * void msgverbset() * * Parces the argument of the MSGVERB environment variable and places * a representation of the value of that value in "msgverb" * * Arguments: * None: * * Returns: void * * Notes: */ static void msgverbset(void) { char *opts; /* Pointer to MSGVERB's value */ char *alloced; /* Pointer to MSGVERB's value */ char *tok; /* Pointer to current token */ char *tokend; /* Pointer to end of current token */ char *nexttok; /* Pointer to next token */ /* Rid ourselves of junk in "msgverb" */ msgverb = 0; /* Get the value of MSGVERB. If none, use default value */ if ((opts = getenv(MSGVERB)) == (char *)NULL) { msgverb = MV_DFLT; } else { /* MSGVERB has a value. Interpret it */ if ((alloced = libc_malloc(strlen(opts) + 1)) == NULL) { msgverb = MV_DFLT; } else { /* Make a copy of the value of MSGVERB */ nexttok = strcpy(alloced, opts); /* Parse the options given by the user */ while ((tok = nexttok) != (char *)NULL) { /* * Find end of the next token and squeeze * out escaped characters */ tokend = exttok(tok, ":"); tok = noesc(tok); /* Delimit token and mark next, if any */ if (*tokend == ':') { nexttok = tokend + (ptrdiff_t)1; *tokend = '\0'; } else { nexttok = (char *)NULL; } /* Check for "text" */ if (strcmp(tok, ST_TXT) == 0) { msgverb |= MV_TXT; /* Check for "label" */ } else if (strcmp(tok, ST_LBL) == 0) { msgverb |= MV_LBL; /* Check for "action */ } else if (strcmp(tok, ST_ACT) == 0) { msgverb |= MV_ACT; /* Check for "severity" */ } else if (strcmp(tok, ST_SEV) == 0) { msgverb |= MV_SEV; /* Check for "tag" */ } else if (strcmp(tok, ST_TAG) == 0) { msgverb |= MV_TAG; /* Unknown, ignore MSGVERB value */ } else { msgverb = MV_DFLT; nexttok = (char *)NULL; } } /* do while */ /* * Use default if no keywords on MSGVERB * environment variable */ if (msgverb == 0) msgverb = MV_DFLT; /* Free allocated space */ libc_free(alloced); } } /* Finished */ /* return; */ } /* * void sevstrset() * * This function builds a structure containing auxillary severity * definitions. * * Arguments: None * * Returns: Void */ static char *sevspace = (char *)NULL; static void sevstrset(void) { struct sevstr *plast; struct sevstr *psev; char *value; /* Look for SEV_LEVEL definition */ if ((value = getenv(SEV_LEVEL)) != (char *)NULL) { /* Allocate space and make a copy of the value of SEV_LEVEL */ if ((sevspace = libc_malloc(strlen(value) + 1)) != NULL) { (void) strcpy(sevspace, value); /* Continue for all severity descriptions */ psev = getauxsevs(sevspace); plast = (struct sevstr *)NULL; if (psev != (struct sevstr *)NULL) { penvsevs = psev; plast = psev; while (psev = getauxsevs((char *)NULL)) { plast->sevnext = psev; plast = psev; } } } /* if sevspace != (char *)NULL */ } /* if value != (char *)NULL */ } /* * int addseverity(value, string) * int value Value of the severity * const char *string Print-string for the severity * * Arguments: * value int * The integer value of the severity being added * string char * * A pointer to the character-string to be printed * whenever a severity of "value" is printed * * Returns: int * Zero if successful, -1 if failed. The function can fail under * the following circumstances: * - libc_malloc() fails * - The "value" is one of the reserved values. * * This function permits C applications to define severity-levels * that augment the standard levels and those defined by the * SEV_LEVEL environment variable. */ int addseverity(int value, const char *string) { struct sevstr *p; /* Temp ptr to severity structs */ struct sevstr *q; /* Temp ptr(follower) to severity */ int found; /* FLAG, element found in the list */ int rtnval; /* Value to return to the caller */ /* Make sure we're not trying to redefine one of the reserved values */ if (value <= 4) { errno = EINVAL; return (-1); } lmutex_lock(&fmt_lock); /* Make sure we've interpreted SEV_LEVEL */ if (sevlook) { sevstrset(); sevlook = FALSE; } /* * Leaf through the list. We may be redefining or removing a * definition */ q = (struct sevstr *)NULL; found = FALSE; for (p = paugsevs; !found && (p != (struct sevstr *)NULL); p = p->sevnext) { if (p->sevvalue == value) { /* We've a match. Remove or modify the entry */ if (string == (char *)NULL) { if (q == (struct sevstr *)NULL) { paugsevs = p->sevnext; } else { q->sevnext = p->sevnext; } libc_free(p); } else { p->sevprstr = string; } found = TRUE; } q = p; } /* Adding a definition */ if (!found && (string != (char *)NULL)) { /* Allocate space for the severity structure */ if ((p = libc_malloc(sizeof (struct sevstr))) == NULL) { lmutex_unlock(&fmt_lock); return (-1); } /* * Fill in the new structure with the data supplied and add to * the head of the augmented severity list. */ p->sevkywd = (char *)NULL; p->sevprstr = string; p->sevvalue = value; p->sevnext = paugsevs; paugsevs = p; /* Successfully added a new severity */ rtnval = 0; } else if (string == (char *)NULL) { /* Attempting to undefined a non-defined severity */ rtnval = -1; errno = EINVAL; } else { /* Successfully redefined a severity */ rtnval = 0; } /* Finished, successful */ lmutex_unlock(&fmt_lock); return (rtnval); } /* * Utility function for converting an integer to a string, avoiding stdio. */ static void itoa(int n, char *s) { char buf[12]; /* 32 bits fits in 10 decimal digits */ char *cp = buf; uint_t un = (n < 0)? -n : n; do { *cp++ = "0123456789"[un % 10]; un /= 10; } while (un); if (n < 0) *s++ = '-'; do { *s++ = *--cp; } while (cp > buf); *s = '\0'; } /* * void writemsg(buf, size, verbosity, label, severity, text, action, tag) * * Arguments: * char *buf The buffer in which to format the message * size_t size The size of the buffer * int verbosity A bit-string that indicates which components * are to be written * const char *label The address of the label-component * int severity The severity value of the message * const char *text The address of the text-component * const char *action The address of the action-component * const char *tag The address of the tag-component * * This function formats the message consisting of the label-component, * severity-component, text-component, action-component, and tag- * component into the provided buffer. The "verbosity" argument * tells which components can be selected. Any or all of the * components can be their null-values. * * Returns: void * * Notes: */ static void writemsg(char *buf, size_t size, int verbosity, const char *label, int severity, const char *text, const char *action, const char *tag) { struct sevstr *psev; /* Ptr for severity str list */ char *p; /* General purpose pointer */ char *sevpstr = NULL; /* Pointer to severity string */ int l1indent; /* # chars to indent line 1 */ int l2indent; /* # chars to indent line 2 */ int textindent; /* # spaces to indent text */ int actindent = 0; /* # spaces to indent action */ int i; /* General purpose counter */ int dolabel; /* TRUE if label to be written */ int dotext; /* TRUE if text to be written */ int dosev; /* TRUE if severity to be written */ int doaction; /* TRUE if action to be written */ int dotag; /* TRUE if tag to be written */ char c; /* Temp, multiuse character */ char sevpstrbuf[15]; /* Space for SV=%d */ char lcllbl[MM_MXLABELLN+1]; /* Space for (possibly */ /* truncated) label */ char lcltag[MM_MXTAGLN+1]; /* Space for (possibly */ /* truncated) tag */ char *ebuf = buf + size - 2; /* * initialize variables. */ sevpstrbuf[0] = (char)0; lcllbl[0] = (char)0; lcltag[0] = (char)0; /* * Figure out what fields are to be written (all are optional) */ dolabel = (verbosity & MV_LBL) && (label != MM_NULLLBL); dosev = (verbosity & MV_SEV) && (severity != MM_NULLSEV); dotext = (verbosity & MV_TXT) && (text != MM_NULLTXT); doaction = (verbosity & MV_ACT) && (action != MM_NULLACT); dotag = (verbosity & MV_TAG) && (tag != MM_NULLTAG); /* * Figure out how much we'll need to indent the text of the message */ /* Count the label of the message, if requested */ textindent = 0; if (dolabel) { (void) strncpy(lcllbl, label, (size_t)MM_MXLABELLN); lcllbl[MM_MXLABELLN] = '\0'; textindent = (int)strlen(lcllbl) + SEPSTRLN; } /* * If severity req'd, determine the severity string and factor * into indent count. Severity string generated by: * 1. Search the standard list of severities. * 2. Search the severities added by the application. * 3. Search the severities added by the environment. * 4. Use the default (SV=n where n is the value of the severity). */ if (dosev) { /* Search the default severity definitions */ psev = pstdsevs; while (psev != (struct sevstr *)NULL) { if (psev->sevvalue == severity) break; psev = psev->sevnext; } if (psev == (struct sevstr *)NULL) { /* * Search the severity definitions * added by the application */ psev = paugsevs; while (psev != (struct sevstr *)NULL) { if (psev->sevvalue == severity) break; psev = psev->sevnext; } if (psev == (struct sevstr *)NULL) { /* * Search the severity definitions * added by the environment */ psev = penvsevs; while (psev != (struct sevstr *)NULL) { if (psev->sevvalue == severity) break; psev = psev->sevnext; } if (psev == (struct sevstr *)NULL) { /* Use default string, SV=severity */ (void) strcpy(sevpstrbuf, "SV="); itoa(severity, &sevpstrbuf[3]); sevpstr = sevpstrbuf; } else { sevpstr = (char *)psev->sevprstr; } } else { sevpstr = (char *)psev->sevprstr; } } else { sevpstr = (char *)psev->sevprstr; } /* Factor into indent counts */ textindent += (int)strlen(sevpstr) + SEPSTRLN; } /* * Figure out the indents. */ if (doaction && dotext) { if (textindent > ACTINTROLN) { l1indent = 0; l2indent = textindent - ACTINTROLN; actindent = textindent; } else { l2indent = 0; actindent = ACTINTROLN; if (dosev || dolabel) { l1indent = ACTINTROLN - textindent; textindent = ACTINTROLN; } else { textindent = 0; l1indent = 0; } } } else { l1indent = 0; l2indent = 0; if (doaction) { actindent = textindent + ACTINTROLN; } else if (dotext) { actindent = 0; } } /* * Write the message. */ /* Write the LABEL, if requested */ if (dolabel) { /* Write spaces to align on the ':' char, if needed */ while (--l1indent >= 0 && buf < ebuf) *buf++ = ' '; /* Write the label */ buf += strlcpy(buf, lcllbl, ebuf - buf); /* * Write the separator string * (if another component is to follow) */ if (dosev || dotext || doaction || dotag) buf += strlcpy(buf, SEPSTR, ebuf - buf); } /* Write the SEVERITY, if requested */ if (dosev) { /* Write spaces to align on the ':' char, if needed */ while (--l1indent >= 0 && buf < ebuf) *buf++ = ' '; /* Write the severity print-string */ buf += strlcpy(buf, sevpstr, ebuf - buf); /* * Write the separator string * (if another component is to follow) */ if (dotext || doaction || dotag) buf += strlcpy(buf, SEPSTR, ebuf - buf); } /* Write the TEXT, if requested */ if (dotext) { p = (char *)text; for (c = *p++; c != NULL && buf < ebuf; c = *p++) { *buf++ = c; if (c == '\n') { for (i = 0; i < textindent && buf < ebuf; i++) *buf++ = ' '; } } } /* * Write ACTION if requested. */ if (doaction) { if (dotext && buf < ebuf) { *buf++ = '\n'; while (--l2indent >= 0 && buf < ebuf) *buf++ = ' '; } /* Write the action-string's introduction */ buf += strlcpy(buf, ACTINTRO, ebuf - buf); /* Write the "action" string */ p = (char *)action; for (c = *p++; c != NULL && buf < ebuf; c = *p++) { *buf++ = c; if (c == '\n') { for (i = 0; i < actindent && buf < ebuf; i++) *buf++ = ' '; } } } /* * Write the TAG if requested */ if (dotag) { if (doaction) buf += strlcpy(buf, " ", ebuf - buf); else if (dotext && buf < ebuf) *buf++ = '\n'; (void) strncpy(lcltag, tag, (size_t)MM_MXTAGLN); lcltag[MM_MXTAGLN] = '\0'; buf += strlcpy(buf, lcltag, ebuf - buf); } /* * Write terminating newline and null byte. * We reserved space for these at the start. */ *buf++ = '\n'; *buf++ = '\0'; } /* * int fmtmsg(class, label, severity, text, action, tag) * long class * const char *label * int severity * const char *text * const char *action * const char *tag * * If requested, the fmtmsg() function writes a message to the standard * error stream in the standard message format. Also if requested, it * will write a message to the system console. * * Arguments: * class Fields which classify the message for the system * logging facility * label A character-string that is printed as the "label" * of the message. Typically identifies the source * of the message * severity Identifies the severity of the message. Either one * of the standard severities, or possibly one of the * augmented severities * text Pointer to the text of the message * action Pointer to a char string that describes some type * of corrective action. * tag A character-string that is printed as the "tag" or * the message. Typically a pointer to documentation * * Returns: * -1 if nothing was generated, 0 if everything requested was * generated, or flags if partially generated. * * Needs: * - Nothing special for 4.0. */ int fmtmsg(long class, const char *label, int severity, const char *text, const char *action, const char *tag) { int rtnval; /* Value to return */ FILE *console; /* Ptr to "console" stream */ char *message1; char *message2; /* * Determine the "verbosity" of the message. If "msgverb" is * already set, don't interrogate the "MSGVERB" environment vbl. * If so, interrogate "MSGVERB" and do initialization stuff also. */ lmutex_lock(&fmt_lock); if (!(msgverb & MV_SET)) { msgverbset(); msgverb |= MV_SET; } /* * Extract the severity definitions from the SEV_LEVEL * environment variable and save away for later. */ if (sevlook) { sevstrset(); sevlook = FALSE; } /* Set up the default text component [if text==(char *)NULL] */ if (text == (char *)NULL) text = DEFLT_TEXT; /* Prepare the message for stderr if requested */ if (class & MM_PRINT) { message1 = alloca(MAX_MSG_SIZE); writemsg(message1, MAX_MSG_SIZE, msgverb, label, severity, text, action, tag); } /* Prepare the message for the console if requested */ if (class & MM_CONSOLE) { message2 = alloca(MAX_MSG_SIZE); writemsg(message2, MAX_MSG_SIZE, MV_ALL, label, severity, text, action, tag); } lmutex_unlock(&fmt_lock); rtnval = MM_OK; /* Write the message to stderr if requested */ if (class & MM_PRINT) { clearerr(stderr); (void) fputs(message1, stderr); if (ferror(stderr)) rtnval |= MM_NOMSG; } /* Write the message to the console if requested */ if (class & MM_CONSOLE) { if ((console = fopen(CONNAME, "wF")) != NULL) { clearerr(console); (void) fputs(message2, console); if (ferror(console)) rtnval |= MM_NOCON; (void) fclose(console); } else { rtnval |= MM_NOCON; } } if ((rtnval & (MM_NOCON | MM_NOMSG)) == (MM_NOCON | MM_NOMSG)) rtnval = MM_NOTOK; return (rtnval); }