1113 lines
27 KiB
C
Executable File
1113 lines
27 KiB
C
Executable File
/* Copyright (c) 1988 AT&T */
|
|
/* All Rights Reserved */
|
|
|
|
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */
|
|
/* The copyright notice above does not evidence any */
|
|
/* actual or intended publication of such source code. */
|
|
|
|
#ident "@(#)fmtmsg.c 1.7 92/09/05 SMI" /* SVr4.0 1.9 */
|
|
|
|
/*LINTLIBRARY*/
|
|
|
|
/*
|
|
* fmtmsg.c
|
|
*
|
|
* Contains:
|
|
* fmtmsg() Writes a message in standard format.
|
|
* addseverity() Adds a severity definition to the list of known
|
|
* severity definitions.
|
|
*
|
|
* Notes:
|
|
* - Using putc() instead of fputc() because putc() is slightly
|
|
* faster (but causes the code to be slightly larger). If space
|
|
* becomes a problem, change putc() to fputc().
|
|
* - None of these functions can use strtok().
|
|
*/
|
|
|
|
/*
|
|
* Header Files Referenced:
|
|
* <stdio.h> C Standard I/O Definitions
|
|
* <string.h> C string handling definitions
|
|
* <fcntl.h> UNIX file control definitions
|
|
* <errno.h> UNIX error numbers and definitions
|
|
* <fmtmsg.h> Global definitions for fmtmsg()
|
|
* <stdlib.h> miscellaneous function declarations
|
|
*/
|
|
|
|
#ifdef __STDC__
|
|
#pragma weak fmtmsg = _fmtmsg
|
|
#pragma weak addseverity = _addseverity
|
|
#endif
|
|
#include "synonyms.h"
|
|
#include "shlib.h"
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <fcntl.h>
|
|
#include <errno.h>
|
|
#include <fmtmsg.h>
|
|
#include <stdlib.h>
|
|
#include <thread.h>
|
|
#include <synch.h>
|
|
#include <mtlib.h>
|
|
|
|
/*
|
|
* External functions referenced:
|
|
* (Others may be defined in header files above)
|
|
*
|
|
* getenv Extracts data from the environment
|
|
* malloc Allocates space from main memory
|
|
* free Frees space allocated via malloc()
|
|
* strtol Convert string to "long"
|
|
* clearerr Clears an error on a stream (this is to make "lint" happy)
|
|
*/
|
|
|
|
#ifdef lint
|
|
extern void clearerr();
|
|
#endif
|
|
|
|
/*
|
|
* 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
|
|
|
|
|
|
/*
|
|
* 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.
|
|
*/
|
|
|
|
#ifdef _REENTRANT
|
|
static mutex_t fmt_lock = DEFAULTMUTEX;
|
|
#endif _REENTRANT
|
|
|
|
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.
|
|
*/
|
|
|
|
#if __STDC__
|
|
static char *
|
|
exttok(const char *tok, const char *delims)
|
|
#else
|
|
static char *
|
|
exttok(tok, delims)
|
|
char *tok; /* Ptr to the token we're parsing */
|
|
char *delims; /* Ptr to string with delimiters */
|
|
#endif
|
|
{
|
|
|
|
/* Automatic Data */
|
|
char *tokend; /* Ptr to the end of the token */
|
|
char *p, *q; /* Temp pointers */
|
|
int done; /* Loop control flag */
|
|
|
|
|
|
/* 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 = tok + strlen(tok);
|
|
|
|
/* Look for the 1st occurrence of any delimiter */
|
|
for (p = delims ; *p != '\0' ; p++) {
|
|
for (q = strchr(tok, *p) ; q && (q != tok) && (*(q-1) == '\\') ; q = strchr(q+1, *p)) ;
|
|
if (q && (q < tokend)) tokend = q;
|
|
}
|
|
|
|
/* Done */
|
|
return(tokend);
|
|
}
|
|
|
|
/*
|
|
* char *noesc(str)
|
|
*
|
|
* This function squeezes out all of the escaped character sequences
|
|
* from the string <str>. 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 <str> always.
|
|
*
|
|
* Notes:
|
|
* This function potentially modifies the string it is given.
|
|
*/
|
|
|
|
static char *
|
|
noesc(str)
|
|
char *str; /* String to remove escaped characters from */
|
|
{
|
|
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(ptr)
|
|
char *ptr;
|
|
{
|
|
|
|
/* Automatic data */
|
|
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
|
|
* <kywd>,<sev>,<printstring> delimited by ':' or '\0'
|
|
*/
|
|
|
|
/* Loop initializations */
|
|
done = FALSE;
|
|
rtnval = (struct sevstr *) NULL;
|
|
while (!done) {
|
|
|
|
/* Eat leading junk */
|
|
while (*(tokend = exttok(current, ":,")) == ':') {
|
|
current = tokend + 1;
|
|
}
|
|
|
|
/* If we've found a <kywd>,... */
|
|
if (*tokend == ',') {
|
|
kywd = current;
|
|
*tokend = '\0';
|
|
|
|
/* Look for <kywd>,<sev>,... */
|
|
current = tokend + 1;
|
|
if (*(tokend = exttok(current, ":,")) == ',') {
|
|
valstr = current;
|
|
*tokend = '\0';
|
|
|
|
current = tokend+1;
|
|
prstr = current;
|
|
|
|
/* Make sure <sev> > 4 */
|
|
val = (int) strtol(noesc(valstr), &p, 0);
|
|
if ((val > 4) && (p == tokend)) {
|
|
|
|
/*
|
|
* Found <kywd>,<sev>,<printstring>.
|
|
* remember where we left off
|
|
*/
|
|
|
|
if (*(tokend = exttok(current, ":")) == ':') {
|
|
*tokend = '\0';
|
|
leftoff = tokend + 1;
|
|
} else leftoff = (char *) NULL;
|
|
|
|
/* Alloc structure to contain severity definition */
|
|
rtnval = (struct sevstr *) malloc(sizeof(struct sevstr));
|
|
if (rtnval != (struct sevstr *) 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()
|
|
{
|
|
/*
|
|
* Automatic data
|
|
*/
|
|
|
|
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;
|
|
|
|
/* MSGVERB has a value. Interpret it */
|
|
else {
|
|
|
|
if (!(alloced = (char *) malloc((unsigned int) strlen(opts)+1))) 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+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 the whole 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 */
|
|
free(alloced);
|
|
|
|
} /* else */
|
|
|
|
}
|
|
|
|
/* 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()
|
|
{
|
|
/* Automatic data */
|
|
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 = (char *) malloc((unsigned int) strlen(value)+1)) {
|
|
(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:
|
|
* - 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(value, string)
|
|
int value;
|
|
const char *string;
|
|
{
|
|
/*
|
|
* Automatic data
|
|
*/
|
|
|
|
struct sevstr *p; /* Temp ptr to severity structs */
|
|
struct sevstr *q; /* Temp ptr (follower) to severity structs */
|
|
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);
|
|
}
|
|
|
|
_mutex_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;
|
|
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 = (struct sevstr *) malloc(sizeof(struct sevstr))) == (struct sevstr *) NULL) {
|
|
_mutex_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 */
|
|
_mutex_unlock(&fmt_lock);
|
|
return(rtnval);
|
|
}
|
|
|
|
/*
|
|
* int writemsg(stream, verbosity, label, severity, text, action, tag)
|
|
*
|
|
* Arguments:
|
|
* FILE *stream The standard I/O stream to which to write
|
|
* the message to
|
|
* 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 writes the message consisting of the label-component,
|
|
* severity-component, text-component, action-component, and tag-
|
|
* component to the standard I/O stream "stream". The "verbosity"
|
|
* argument tells which components can be selected. Any or all of the
|
|
* components can be their null-values.
|
|
*
|
|
* Returns: int
|
|
* 0 if no error was encountered,
|
|
* !0 if an error was encountered
|
|
*
|
|
* Notes:
|
|
*/
|
|
|
|
static int
|
|
writemsg(stream, verbosity, label, severity, text, action, tag)
|
|
FILE *stream; /* Stream to write the message to */
|
|
int verbosity; /* Components to include in the message */
|
|
const char *label; /* Label-component */
|
|
const char *text; /* Text-component */
|
|
const char *action; /* Action-component */
|
|
const char *tag; /* Tag-component */
|
|
int severity; /* Severity value */
|
|
{
|
|
struct sevstr *psev; /* Ptr for severity str list */
|
|
const char *p; /* General purpose pointer */
|
|
const char *sevpstr; /* 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; /* # 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 */
|
|
|
|
|
|
/*
|
|
* 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, MM_MXLABELLN);
|
|
lcllbl[MM_MXLABELLN] = '\0';
|
|
textindent = 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;
|
|
else 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;
|
|
else 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;
|
|
else psev = psev->sevnext;
|
|
|
|
if (psev == (struct sevstr *) NULL) {
|
|
|
|
/* Use default string, SV=severity */
|
|
(void) sprintf(sevpstrbuf, "SV=%d", severity);
|
|
sevpstr = sevpstrbuf;
|
|
|
|
}
|
|
else sevpstr = psev->sevprstr;
|
|
|
|
}
|
|
else sevpstr = psev->sevprstr;
|
|
|
|
}
|
|
else sevpstr = psev->sevprstr;
|
|
|
|
/* Factor into indent counts */
|
|
textindent += 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;
|
|
}
|
|
}
|
|
|
|
/* No characters written yet, no errors either */
|
|
clearerr(stream);
|
|
|
|
|
|
/*
|
|
* Write the message.
|
|
*/
|
|
|
|
|
|
/* Write the LABEL, if requested */
|
|
if (dolabel) {
|
|
|
|
/* Write spaces to align on the ':' char, if needed */
|
|
while (--l1indent >= 0) (void) putc(' ', stream);
|
|
|
|
/* Write the label */
|
|
(void) fputs(lcllbl, stream);
|
|
|
|
/* Write the separator string (if another component is to follow) */
|
|
if (dosev || dotext || doaction || dotag)
|
|
(void) fputs(SEPSTR, stream);
|
|
}
|
|
|
|
/* Write the SEVERITY, if requested */
|
|
if (dosev) {
|
|
|
|
/* Write spaces to align on the ':' char, if needed */
|
|
while (--l1indent >= 0) (void) putc(' ', stream);
|
|
|
|
/* Write the severity print-string */
|
|
(void) fputs(sevpstr, stream);
|
|
|
|
/* Write the separator string (if another component is to follow) */
|
|
if (dotext || doaction || dotag)
|
|
(void) fputs(SEPSTR, stream);
|
|
}
|
|
|
|
/* Write the TEXT, if requested */
|
|
if (dotext) {
|
|
p = text;
|
|
while (c = *p++) {
|
|
(void) putc(c, stream);
|
|
if (c == '\n') {
|
|
for (i = 0 ; i < textindent ; i++)
|
|
(void) putc(' ', stream);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Write ACTION if requested.
|
|
*/
|
|
|
|
if (doaction) {
|
|
if (dotext) {
|
|
(void) putc('\n', stream);
|
|
while (--l2indent >= 0) {
|
|
(void) putc(' ', stream);
|
|
}
|
|
}
|
|
|
|
/* Write the action-string's introduction */
|
|
(void) fputs(ACTINTRO, stream);
|
|
|
|
/* Write the "action" string */
|
|
p = action;
|
|
while (c = *p++) {
|
|
(void) putc(c, stream);
|
|
if (c == '\n') {
|
|
for (i = 0 ; i < actindent ; i++)
|
|
(void) putc(' ', stream);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Write the TAG if requested
|
|
*/
|
|
|
|
if (dotag) {
|
|
|
|
if (doaction) (void) fputs(" ", stream);
|
|
else if (dotext) (void) putc('\n', stream);
|
|
(void) strncpy(lcltag, tag, MM_MXTAGLN);
|
|
lcltag[MM_MXTAGLN] = '\0';
|
|
(void) fputs(lcltag, stream);
|
|
}
|
|
|
|
/* Write terminating carriage control */
|
|
(void) putc('\n', stream);
|
|
|
|
return(ferror(stream));
|
|
}
|
|
|
|
/*
|
|
* 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(class, label, severity, text, action, tag)
|
|
long class; /* Message "classification" */
|
|
int severity; /* Message "severity" */
|
|
const char *label; /* Ptr to "label" */
|
|
const char *text; /* Ptr to the "text" */
|
|
const char *action; /* Ptr to the text of the "action" */
|
|
const char *tag; /* Ptr to the "tag" */
|
|
{
|
|
|
|
/* Local automatic data */
|
|
int rtnval; /* Value to return */
|
|
FILE *console; /* Ptr to "console" stream */
|
|
|
|
|
|
/*
|
|
* 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.
|
|
*/
|
|
|
|
_mutex_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;
|
|
|
|
rtnval = MM_OK;
|
|
|
|
|
|
/* Write the message to stderr if requested */
|
|
if (class & MM_PRINT) {
|
|
if (writemsg(stderr, msgverb, label, severity, text, action, tag)) rtnval |= MM_NOMSG;
|
|
}
|
|
|
|
/* Write the message to the console if requested */
|
|
if (class & MM_CONSOLE) {
|
|
if (console = fopen(CONNAME, "w")) {
|
|
if (writemsg(console, MV_ALL, label, severity, text, action, tag)) rtnval |= MM_NOCON;
|
|
(void) fclose(console);
|
|
}
|
|
else rtnval |= MM_NOCON;
|
|
}
|
|
|
|
if ((rtnval & (MM_NOCON | MM_NOMSG)) == (MM_NOCON | MM_NOMSG)) rtnval = MM_NOTOK;
|
|
_mutex_unlock(&fmt_lock);
|
|
return (rtnval);
|
|
}
|