xref: /onnv-gate/usr/src/lib/libc/port/gen/fmtmsg.c (revision 6812:febeba71273d)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51914Scasper  * Common Development and Distribution License (the "License").
61914Scasper  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
21*6812Sraf 
220Sstevel@tonic-gate /*
23*6812Sraf  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate /*	Copyright (c) 1988 AT&T	*/
280Sstevel@tonic-gate /*	  All Rights Reserved  	*/
290Sstevel@tonic-gate 
30*6812Sraf #pragma ident	"%Z%%M%	%I%	%E% SMI"
310Sstevel@tonic-gate 
320Sstevel@tonic-gate /*
330Sstevel@tonic-gate  * fmtmsg.c
340Sstevel@tonic-gate  *
350Sstevel@tonic-gate  *  Contains:
360Sstevel@tonic-gate  *	fmtmsg()	Writes a message in standard format.
370Sstevel@tonic-gate  *	addseverity()	Adds a severity definition to the list of known
380Sstevel@tonic-gate  *			severity definitions.
390Sstevel@tonic-gate  *
400Sstevel@tonic-gate  *	Notes:
410Sstevel@tonic-gate  *	  - None of these functions can use strtok().
420Sstevel@tonic-gate  */
430Sstevel@tonic-gate 
440Sstevel@tonic-gate /*
450Sstevel@tonic-gate  * Header Files Referenced:
460Sstevel@tonic-gate  *	<stdio.h>		C Standard I/O Definitions
470Sstevel@tonic-gate  *	<string.h>		C string handling definitions
480Sstevel@tonic-gate  *	<fcntl.h>		UNIX file control definitions
490Sstevel@tonic-gate  *	<errno.h>		UNIX error numbers and definitions
500Sstevel@tonic-gate  *	<fmtmsg.h>		Global definitions for fmtmsg()
510Sstevel@tonic-gate  *	<stdlib.h>		miscellaneous function declarations
520Sstevel@tonic-gate  */
530Sstevel@tonic-gate 
54*6812Sraf #pragma weak _fmtmsg = fmtmsg
55*6812Sraf #pragma weak _addseverity = addseverity
56*6812Sraf 
57*6812Sraf #include "lint.h"
580Sstevel@tonic-gate #include "mtlib.h"
590Sstevel@tonic-gate #include "libc.h"
600Sstevel@tonic-gate #include <sys/types.h>
610Sstevel@tonic-gate #include <stddef.h>
620Sstevel@tonic-gate #include <stdio.h>
630Sstevel@tonic-gate #include <string.h>
640Sstevel@tonic-gate #include <fcntl.h>
650Sstevel@tonic-gate #include <errno.h>
660Sstevel@tonic-gate #include <fmtmsg.h>
670Sstevel@tonic-gate #include <stdlib.h>
680Sstevel@tonic-gate #include <thread.h>
690Sstevel@tonic-gate #include <synch.h>
700Sstevel@tonic-gate #include <alloca.h>
710Sstevel@tonic-gate 
720Sstevel@tonic-gate /*
730Sstevel@tonic-gate  * External functions referenced:
740Sstevel@tonic-gate  *	(Others may be defined in header files above)
750Sstevel@tonic-gate  *
760Sstevel@tonic-gate  *	getenv		Extracts data from the environment
770Sstevel@tonic-gate  *	libc_malloc	Allocates space from main memory
780Sstevel@tonic-gate  *	libc_free	Frees space allocated via libc_malloc()
790Sstevel@tonic-gate  *	strtol		Convert string to "long"
800Sstevel@tonic-gate  *	clearerr	Clears an error on a stream (this is to make "lint"
810Sstevel@tonic-gate  *			happy)
820Sstevel@tonic-gate  */
830Sstevel@tonic-gate 
840Sstevel@tonic-gate 
850Sstevel@tonic-gate /*
860Sstevel@tonic-gate  * Local Constant Definitions
870Sstevel@tonic-gate  */
880Sstevel@tonic-gate 
890Sstevel@tonic-gate /*
900Sstevel@tonic-gate  * Boolean constants
910Sstevel@tonic-gate  *	TRUE	Boolean value for "true" (any bits on)
920Sstevel@tonic-gate  *	FALSE	Boolean value for "false" (all bits off)
930Sstevel@tonic-gate  */
940Sstevel@tonic-gate 
950Sstevel@tonic-gate #ifndef	FALSE
960Sstevel@tonic-gate #define	FALSE		(0)
970Sstevel@tonic-gate #endif
980Sstevel@tonic-gate 
990Sstevel@tonic-gate #ifndef TRUE
1000Sstevel@tonic-gate #define	TRUE		(1)
1010Sstevel@tonic-gate #endif
1020Sstevel@tonic-gate 
1030Sstevel@tonic-gate #define	MAX_MSG_SIZE	1024
1040Sstevel@tonic-gate 
1050Sstevel@tonic-gate /*
1060Sstevel@tonic-gate  * Keywords for fields named in the MSGVERB environment variable.
1070Sstevel@tonic-gate  */
1080Sstevel@tonic-gate 
1090Sstevel@tonic-gate #define	ST_LBL		"label"
1100Sstevel@tonic-gate #define	ST_SEV		"severity"
1110Sstevel@tonic-gate #define	ST_TXT		"text"
1120Sstevel@tonic-gate #define	ST_TAG		"tag"
1130Sstevel@tonic-gate #define	ST_ACT		"action"
1140Sstevel@tonic-gate 
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate /*
1170Sstevel@tonic-gate  *	The following constants define the value of the "msgverb"
1180Sstevel@tonic-gate  *	variable.  This variable tells fmtmsg() which parts of the
1190Sstevel@tonic-gate  *	standard message it is to display.  If !(msgverb&MV_SET),
1200Sstevel@tonic-gate  *	fmtmsg() will interrogate the "MSGVERB" environment variable
1210Sstevel@tonic-gate  *	and set "msgverb" accordingly.
1220Sstevel@tonic-gate  *
1230Sstevel@tonic-gate  *	NOTE:  This means that if MSGVERB changes after the first call
1240Sstevel@tonic-gate  *	       to fmtmsg(), it will be ignored.
1250Sstevel@tonic-gate  *
1260Sstevel@tonic-gate  *	Constants:
1270Sstevel@tonic-gate  *		MV_INV	Check MSGVERB environment variable (invalidates value)
1280Sstevel@tonic-gate  *		MV_SET	MSGVERB checked, msgverb value valid
1290Sstevel@tonic-gate  *		MV_LBL	"label" selected
1300Sstevel@tonic-gate  *		MV_SEV	"severity" selected
1310Sstevel@tonic-gate  *		MV_TXT	"text" selected
1320Sstevel@tonic-gate  *		MV_TAG	"messageID" selected
1330Sstevel@tonic-gate  *		MV_ACT	"action" selected
1340Sstevel@tonic-gate  *
1350Sstevel@tonic-gate  *		MV_ALL	All components selected
1360Sstevel@tonic-gate  *		MV_DFLT	Default value for MSGVERB
1370Sstevel@tonic-gate  */
1380Sstevel@tonic-gate 
1390Sstevel@tonic-gate #define	MV_INV		0
1400Sstevel@tonic-gate #define	MV_SET		0x0001
1410Sstevel@tonic-gate #define	MV_LBL		0x0002
1420Sstevel@tonic-gate #define	MV_SEV		0x0004
1430Sstevel@tonic-gate #define	MV_TXT		0x0008
1440Sstevel@tonic-gate #define	MV_TAG		0x0010
1450Sstevel@tonic-gate #define	MV_ACT		0x0020
1460Sstevel@tonic-gate 
1470Sstevel@tonic-gate #define	MV_ALL		(MV_LBL|MV_SEV|MV_TXT|MV_TAG|MV_ACT)
1480Sstevel@tonic-gate #define	MV_DFLT		(MV_LBL|MV_SEV|MV_TXT|MV_TAG|MV_ACT)
1490Sstevel@tonic-gate 
1500Sstevel@tonic-gate 
1510Sstevel@tonic-gate 
1520Sstevel@tonic-gate /*
1530Sstevel@tonic-gate  * Strings defining the different severities of a message.
1540Sstevel@tonic-gate  * Internationalization may demand that these come from the message database
1550Sstevel@tonic-gate  */
1560Sstevel@tonic-gate 
1570Sstevel@tonic-gate #define	SV_UNK		"UNKNOWN"
1580Sstevel@tonic-gate #define	SV_HALT		"HALT"
1590Sstevel@tonic-gate #define	SV_ERROR	"ERROR"
1600Sstevel@tonic-gate #define	SV_WARN		"WARNING"
1610Sstevel@tonic-gate #define	SV_INF		"INFO"
1620Sstevel@tonic-gate 
1630Sstevel@tonic-gate 
1640Sstevel@tonic-gate /*
1650Sstevel@tonic-gate  * Text string if none is provided:
1660Sstevel@tonic-gate  */
1670Sstevel@tonic-gate 
1680Sstevel@tonic-gate #define	DEFLT_TEXT	"No text provided with this message"
1690Sstevel@tonic-gate 
1700Sstevel@tonic-gate 
1710Sstevel@tonic-gate /*
1720Sstevel@tonic-gate  * Text string introduction for "action".  This may have to come from
1730Sstevel@tonic-gate  * the message database because of internationalization.
1740Sstevel@tonic-gate  */
1750Sstevel@tonic-gate 
1760Sstevel@tonic-gate #define	ACTINTRO	"TO FIX: "
1770Sstevel@tonic-gate #define	ACTINTROLN	8
1780Sstevel@tonic-gate 
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate /*
1810Sstevel@tonic-gate  * SEPSTR is the string that separates the "label" from what follows it,
1820Sstevel@tonic-gate  * and the severity from what follows it.
1830Sstevel@tonic-gate  */
1840Sstevel@tonic-gate 
1850Sstevel@tonic-gate #define	SEPSTR		": "
1860Sstevel@tonic-gate #define	SEPSTRLN	2
1870Sstevel@tonic-gate 
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate /*
1900Sstevel@tonic-gate  * Miscellaneous constants:
1910Sstevel@tonic-gate  *	CONNAME		Filesystem entry name for the system console
1920Sstevel@tonic-gate  */
1930Sstevel@tonic-gate 
1940Sstevel@tonic-gate #define	CONNAME		"/dev/console"
1950Sstevel@tonic-gate 
1960Sstevel@tonic-gate /*
1970Sstevel@tonic-gate  * Local data type definitions
1980Sstevel@tonic-gate  */
1990Sstevel@tonic-gate 
2000Sstevel@tonic-gate /*
2010Sstevel@tonic-gate  * Severity string structure
2020Sstevel@tonic-gate  *
2030Sstevel@tonic-gate  *	struct sevstr
2040Sstevel@tonic-gate  *		sevvalue	Value of the severity-level being defined
2050Sstevel@tonic-gate  *		sevkywd		Keyword identifying the severity
2060Sstevel@tonic-gate  *		sevprptr	Pointer to the string associated with the value
2070Sstevel@tonic-gate  *		sevnext		Pointer to the next value in the list.
2080Sstevel@tonic-gate  *
2090Sstevel@tonic-gate  *	Restrictions:
2100Sstevel@tonic-gate  *		sevvalue	Must be a non-negative integer (>=0)
2110Sstevel@tonic-gate  *
2120Sstevel@tonic-gate  *	There are three (possibly null) lists of these structures.
2130Sstevel@tonic-gate  *	  1)	is the list of standard severities
2140Sstevel@tonic-gate  *	  2)	is the list of severity-levels defined by SEV_LEVEL
2150Sstevel@tonic-gate  *	  3)	is the list of severity-levels defined by calls to
2160Sstevel@tonic-gate  *		addseverity()
2170Sstevel@tonic-gate  */
2180Sstevel@tonic-gate 
2190Sstevel@tonic-gate struct sevstr {
2200Sstevel@tonic-gate 	int		sevvalue;
2210Sstevel@tonic-gate 	const char	*sevkywd;
2220Sstevel@tonic-gate 	const char	*sevprstr;
2230Sstevel@tonic-gate 	struct sevstr  *sevnext;
2240Sstevel@tonic-gate };
2250Sstevel@tonic-gate 
2260Sstevel@tonic-gate /*
2270Sstevel@tonic-gate  * Local Static Data
2280Sstevel@tonic-gate  *	msgverb		int
2290Sstevel@tonic-gate  *			Contains the internal representation or the
2300Sstevel@tonic-gate  *			MSGVERB environment variable.
2310Sstevel@tonic-gate  *	sevlook		TRUE if fmtmsg() has to look at SEV_LEVEL the
2320Sstevel@tonic-gate  *			next time it is called.
2330Sstevel@tonic-gate  *	paugsevs	struct sevstr *
2340Sstevel@tonic-gate  *			Head of the linked list of structures that define
2350Sstevel@tonic-gate  *			severities that augment the standard severities,
2360Sstevel@tonic-gate  *			as defined by addseverity().
2370Sstevel@tonic-gate  *	penvsevs	struct sevstrs *
2380Sstevel@tonic-gate  *			Head of the linked list of structures that define
2390Sstevel@tonic-gate  *			severities that augment the standard severities,
2400Sstevel@tonic-gate  *			as defined by SEV_LEVEL.
2410Sstevel@tonic-gate  *	pstdsevs	struct sevstrs *
2420Sstevel@tonic-gate  *			Head of the linked list of structures that define
2430Sstevel@tonic-gate  *			the standard severities.
2440Sstevel@tonic-gate  */
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate static mutex_t fmt_lock = DEFAULTMUTEX;
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate static	int		msgverb		= 0;
2490Sstevel@tonic-gate static	int		sevlook		= TRUE;
2500Sstevel@tonic-gate 
2510Sstevel@tonic-gate static	struct sevstr  *paugsevs	= (struct sevstr *)NULL;
2520Sstevel@tonic-gate static	struct sevstr  *penvsevs	= (struct sevstr *)NULL;
2530Sstevel@tonic-gate 
2540Sstevel@tonic-gate static	struct sevstr	sevstrs[]	= {
2550Sstevel@tonic-gate 	{ MM_HALT,	"", SV_HALT,	&sevstrs[1]},
2560Sstevel@tonic-gate 	{ MM_ERROR,    "", SV_ERROR,	&sevstrs[2]},
2570Sstevel@tonic-gate 	{ MM_WARNING,  "", SV_WARN, 	&sevstrs[3]},
2580Sstevel@tonic-gate 	{ MM_INFO,	"", SV_INF,  	(struct sevstr *)NULL},
2590Sstevel@tonic-gate };
2600Sstevel@tonic-gate static	struct sevstr  *pstdsevs	= &sevstrs[0];
2610Sstevel@tonic-gate 
2620Sstevel@tonic-gate /*
2630Sstevel@tonic-gate  * static char *exttok(str, delims)
2640Sstevel@tonic-gate  *	const char   *str
2650Sstevel@tonic-gate  *	const char   *delims
2660Sstevel@tonic-gate  *
2670Sstevel@tonic-gate  *	This function examines the string pointed to by "str", looking
2680Sstevel@tonic-gate  *	for the first occurrence of any of the characters in the string
2690Sstevel@tonic-gate  *	whose address is "delims".  It returns the address of that
2700Sstevel@tonic-gate  *	character or (char *)NULL if there was nothing to search.
2710Sstevel@tonic-gate  *
2720Sstevel@tonic-gate  * Arguments:
2730Sstevel@tonic-gate  *	str	Address of the string to search
2740Sstevel@tonic-gate  *	delims	Address of the string containing delimiters
2750Sstevel@tonic-gate  *
2760Sstevel@tonic-gate  * Returns:  char *
2770Sstevel@tonic-gate  *	Returns the address of the first occurrence of any of the characters
2780Sstevel@tonic-gate  *	in "delim" in the string "str" (incl '\0').  If there was nothing
2790Sstevel@tonic-gate  *	to search, the function returns (char *)NULL.
2800Sstevel@tonic-gate  *
2810Sstevel@tonic-gate  * Notes:
2820Sstevel@tonic-gate  *    - This function is needed because strtok() can't be used inside a
2830Sstevel@tonic-gate  *	function.  Besides, strtok() is destructive in the string, which
2840Sstevel@tonic-gate  *	is undesirable in many circumstances.
2850Sstevel@tonic-gate  *    - This function understands escaped delimiters as non-delimiters.
2860Sstevel@tonic-gate  *	Delimiters are escaped by preceding them with '\' characters.
2870Sstevel@tonic-gate  *	The '\' character also must be escaped.
2880Sstevel@tonic-gate  */
2890Sstevel@tonic-gate 
2900Sstevel@tonic-gate static char *
exttok(const char * tok,const char * delims)2910Sstevel@tonic-gate exttok(const char *tok, const char *delims)
2920Sstevel@tonic-gate {
2930Sstevel@tonic-gate 	char	*tokend;	/* Ptr to the end of the token */
2940Sstevel@tonic-gate 	char	*p, *q;		/* Temp pointers */
2950Sstevel@tonic-gate 
2960Sstevel@tonic-gate 	/*
2970Sstevel@tonic-gate 	 * Algorithm:
2980Sstevel@tonic-gate 	 *    1.  Get the starting address(new string or where we
2990Sstevel@tonic-gate 	 *	  left off).  If nothing to search, return(char *)NULL
3000Sstevel@tonic-gate 	 *    2.  Find the end of the string
3010Sstevel@tonic-gate 	 *    3.  Look for the first unescaped delimiter closest to the
3020Sstevel@tonic-gate 	 *	  beginning of the string
3030Sstevel@tonic-gate 	 *    4.  Remember where we left off
3040Sstevel@tonic-gate 	 *    5.  Return a pointer to the delimiter we found
3050Sstevel@tonic-gate 	 */
3060Sstevel@tonic-gate 
3070Sstevel@tonic-gate 	/* Begin at the beginning, if any */
3080Sstevel@tonic-gate 	if (tok == (char *)NULL) {
3090Sstevel@tonic-gate 		return ((char *)NULL);
3100Sstevel@tonic-gate 	}
3110Sstevel@tonic-gate 
3120Sstevel@tonic-gate 	/* Find end of the token string */
3130Sstevel@tonic-gate 	tokend = (char *)tok + (ptrdiff_t)strlen(tok);
3140Sstevel@tonic-gate 
3150Sstevel@tonic-gate 	/* Look for the 1st occurrence of any delimiter */
3160Sstevel@tonic-gate 	for (p = (char *)delims; *p != '\0'; p++) {
3170Sstevel@tonic-gate 		for (q = strchr(tok, (int)*p);
3180Sstevel@tonic-gate 		    (q != 0) && (q != tok) && (*(q - (ptrdiff_t)1) == '\\');
3190Sstevel@tonic-gate 		    q = strchr(q + (ptrdiff_t)1, (int)*p))
3200Sstevel@tonic-gate 			;
3210Sstevel@tonic-gate 		if ((q != 0) && (q < tokend))
3220Sstevel@tonic-gate 			tokend = q;
3230Sstevel@tonic-gate 	}
3240Sstevel@tonic-gate 
3250Sstevel@tonic-gate 	/* Done */
3260Sstevel@tonic-gate 	return (tokend);
3270Sstevel@tonic-gate }
3280Sstevel@tonic-gate 
3290Sstevel@tonic-gate /*
3300Sstevel@tonic-gate  * char *noesc(str)
3310Sstevel@tonic-gate  *
3320Sstevel@tonic-gate  *	This function squeezes out all of the escaped character sequences
3330Sstevel@tonic-gate  *	from the string <str>.  It returns a pointer to that string.
3340Sstevel@tonic-gate  *
3350Sstevel@tonic-gate  *  Arguments:
3360Sstevel@tonic-gate  *	str	char *
3370Sstevel@tonic-gate  *		The string that is to have its escaped characters removed.
3380Sstevel@tonic-gate  *
3390Sstevel@tonic-gate  *  Returns:  char *
3400Sstevel@tonic-gate  *	This function returns its argument <str> always.
3410Sstevel@tonic-gate  *
3420Sstevel@tonic-gate  *  Notes:
3430Sstevel@tonic-gate  *	This function potentially modifies the string it is given.
3440Sstevel@tonic-gate  */
3450Sstevel@tonic-gate 
3460Sstevel@tonic-gate static char *
noesc(char * str)3470Sstevel@tonic-gate noesc(char *str)
3480Sstevel@tonic-gate {
3490Sstevel@tonic-gate 	char   *p;		/* Temp string pointer */
3500Sstevel@tonic-gate 	char   *q;		/* Temp string pointer */
3510Sstevel@tonic-gate 
3520Sstevel@tonic-gate 	/* Look for an escaped character */
3530Sstevel@tonic-gate 	p = str;
3540Sstevel@tonic-gate 	while (*p && (*p != '\\')) p++;
3550Sstevel@tonic-gate 
3560Sstevel@tonic-gate 
3570Sstevel@tonic-gate 	/*
3580Sstevel@tonic-gate 	 * If there was at least one, squeeze them out
3590Sstevel@tonic-gate 	 * Otherwise, don't touch the argument string
3600Sstevel@tonic-gate 	 */
3610Sstevel@tonic-gate 
3620Sstevel@tonic-gate 	if (*p) {
3630Sstevel@tonic-gate 		q = p++;
3640Sstevel@tonic-gate 		while (*q++ = *p++) {
3650Sstevel@tonic-gate 			if (*p == '\\')
3660Sstevel@tonic-gate 				p++;
3670Sstevel@tonic-gate 		}
3680Sstevel@tonic-gate 	}
3690Sstevel@tonic-gate 
3700Sstevel@tonic-gate 	/* Finished.  Return our argument */
3710Sstevel@tonic-gate 	return (str);
3720Sstevel@tonic-gate }
3730Sstevel@tonic-gate 
3740Sstevel@tonic-gate /*
3750Sstevel@tonic-gate  * struct sevstr *getauxsevs(ptr)
3760Sstevel@tonic-gate  *
3770Sstevel@tonic-gate  *	Parses a string that is in the format of the severity definitions.
3780Sstevel@tonic-gate  *	Returns a pointer to a (malloc'd) structure that contains the
3790Sstevel@tonic-gate  *	definition, or (struct sevstr *)NULL if none was parsed.
3800Sstevel@tonic-gate  *
3810Sstevel@tonic-gate  * Arguments:
3820Sstevel@tonic-gate  *	ptr	char *
3830Sstevel@tonic-gate  *		References the string from which data is to be extracted.
3840Sstevel@tonic-gate  *		If (char *)NULL, continue where we left off.  Otherwise,
3850Sstevel@tonic-gate  *		start with the string referenced by ptr.
3860Sstevel@tonic-gate  *
3870Sstevel@tonic-gate  * Returns: struct sevstr *
3880Sstevel@tonic-gate  *	A pointer to a malloc'd structure containing the severity definition
3890Sstevel@tonic-gate  *	parsed from string, or (struct sevstr *)NULL if none.
3900Sstevel@tonic-gate  *
3910Sstevel@tonic-gate  * Notes:
3920Sstevel@tonic-gate  *    - This function is destructive to the string referenced by its argument.
3930Sstevel@tonic-gate  */
3940Sstevel@tonic-gate 
3950Sstevel@tonic-gate /* Static data */
3960Sstevel@tonic-gate static	char		*leftoff = (char *)NULL;
3970Sstevel@tonic-gate 
3980Sstevel@tonic-gate static	struct sevstr *
getauxsevs(char * ptr)3990Sstevel@tonic-gate getauxsevs(char *ptr)
4000Sstevel@tonic-gate {
4010Sstevel@tonic-gate 	char		*current;	/* Ptr to current sev def'n */
4020Sstevel@tonic-gate 	char		*tokend;	/* Ptr to end of current sev def'n */
4030Sstevel@tonic-gate 	char		*kywd;		/* Ptr to extracted kywd */
4040Sstevel@tonic-gate 	char		*valstr;		/* Ptr to extracted sev value */
4050Sstevel@tonic-gate 	char		*prstr;		/* Ptr to extracted print str */
4060Sstevel@tonic-gate 	char		*p;		/* Temp pointer */
4070Sstevel@tonic-gate 	int		val;		/* Converted severity value */
4080Sstevel@tonic-gate 	int		done;		/* Flag, sev def'n found and ok? */
4090Sstevel@tonic-gate 	struct sevstr  *rtnval;		/* Value to return */
4100Sstevel@tonic-gate 
4110Sstevel@tonic-gate 
4120Sstevel@tonic-gate 	/* Start anew or start where we left off? */
4130Sstevel@tonic-gate 	current = (ptr == (char *)NULL) ? leftoff : ptr;
4140Sstevel@tonic-gate 
4150Sstevel@tonic-gate 
4160Sstevel@tonic-gate 	/* If nothing to parse, return (char *)NULL */
4170Sstevel@tonic-gate 	if (current == (char *)NULL) {
4180Sstevel@tonic-gate 		return ((struct sevstr *)NULL);
4190Sstevel@tonic-gate 	}
4200Sstevel@tonic-gate 
4210Sstevel@tonic-gate 
4220Sstevel@tonic-gate 	/*
4230Sstevel@tonic-gate 	 * Look through the string "current" for a token of the form
4240Sstevel@tonic-gate 	 * <kywd>,<sev>,<printstring> delimited by ':' or '\0'
4250Sstevel@tonic-gate 	 */
4260Sstevel@tonic-gate 
4270Sstevel@tonic-gate 	/* Loop initializations */
4280Sstevel@tonic-gate 	done = FALSE;
4290Sstevel@tonic-gate 	rtnval = (struct sevstr *)NULL;
4300Sstevel@tonic-gate 	while (!done) {
4310Sstevel@tonic-gate 		/* Eat leading junk */
4320Sstevel@tonic-gate 		while (*(tokend = exttok(current, ":,")) == ':') {
4330Sstevel@tonic-gate 			current = tokend + (ptrdiff_t)1;
4340Sstevel@tonic-gate 		}
4350Sstevel@tonic-gate 
4360Sstevel@tonic-gate 		/* If we've found a <kywd>,... */
4370Sstevel@tonic-gate 		if (*tokend == ',') {
4380Sstevel@tonic-gate 			kywd = current;
4390Sstevel@tonic-gate 			*tokend = '\0';
4400Sstevel@tonic-gate 
4410Sstevel@tonic-gate 			/* Look for <kywd>,<sev>,... */
4420Sstevel@tonic-gate 			current = tokend + (ptrdiff_t)1;
4430Sstevel@tonic-gate 			if (*(tokend = exttok(current, ":,")) == ',') {
4440Sstevel@tonic-gate 				valstr = current;
4450Sstevel@tonic-gate 				*tokend = '\0';
4460Sstevel@tonic-gate 
4470Sstevel@tonic-gate 				current = tokend + (ptrdiff_t)1;
4480Sstevel@tonic-gate 				prstr = current;
4490Sstevel@tonic-gate 
4500Sstevel@tonic-gate 				/* Make sure <sev> > 4 */
4510Sstevel@tonic-gate 				val = (int)strtol(noesc(valstr), &p, 0);
4520Sstevel@tonic-gate 				if ((val > 4) && (p == tokend)) {
4530Sstevel@tonic-gate 
4540Sstevel@tonic-gate 					/*
4550Sstevel@tonic-gate 					 * Found <kywd>,<sev>,<printstring>.
4560Sstevel@tonic-gate 					 * remember where we left off
4570Sstevel@tonic-gate 					 */
4580Sstevel@tonic-gate 
4590Sstevel@tonic-gate 					if (*(tokend =
460*6812Sraf 					    exttok(current, ":")) == ':') {
4610Sstevel@tonic-gate 						*tokend = '\0';
4620Sstevel@tonic-gate 						leftoff = tokend +
4630Sstevel@tonic-gate 						    (ptrdiff_t)1;
4640Sstevel@tonic-gate 					} else {
4650Sstevel@tonic-gate 						leftoff = (char *)NULL;
4660Sstevel@tonic-gate 					}
4670Sstevel@tonic-gate 
4680Sstevel@tonic-gate 					/*
4690Sstevel@tonic-gate 					 * Alloc structure to contain
4700Sstevel@tonic-gate 					 * severity definition
4710Sstevel@tonic-gate 					 */
4720Sstevel@tonic-gate 					rtnval = libc_malloc(
4730Sstevel@tonic-gate 					    sizeof (struct sevstr));
4740Sstevel@tonic-gate 					if (rtnval != NULL) {
4750Sstevel@tonic-gate 
4760Sstevel@tonic-gate 						/* Fill in structure */
4770Sstevel@tonic-gate 						rtnval->sevkywd = noesc(kywd);
4780Sstevel@tonic-gate 						rtnval->sevvalue = val;
4790Sstevel@tonic-gate 						rtnval->sevprstr = noesc(prstr);
4800Sstevel@tonic-gate 						rtnval->sevnext =
4810Sstevel@tonic-gate 						    (struct sevstr *)NULL;
4820Sstevel@tonic-gate 					}
4830Sstevel@tonic-gate 					done = TRUE;
4840Sstevel@tonic-gate 				} else {
4850Sstevel@tonic-gate 					/*
4860Sstevel@tonic-gate 					 * Invalid severity value,
4870Sstevel@tonic-gate 					 * eat thru end of token
4880Sstevel@tonic-gate 					 */
4890Sstevel@tonic-gate 					current = tokend;
4900Sstevel@tonic-gate 					if (*(tokend = exttok(prstr, ":")) ==
4910Sstevel@tonic-gate 					    ':') {
4920Sstevel@tonic-gate 						current++;
4930Sstevel@tonic-gate 					}
4940Sstevel@tonic-gate 				}
4950Sstevel@tonic-gate 			} else {
4960Sstevel@tonic-gate 				/*
4970Sstevel@tonic-gate 				 * Invalid severity definition,
4980Sstevel@tonic-gate 				 * eat thru end of token
4990Sstevel@tonic-gate 				 */
5000Sstevel@tonic-gate 				current = tokend;
5010Sstevel@tonic-gate 				if (*tokend == ':')
5020Sstevel@tonic-gate 					current++;
5030Sstevel@tonic-gate 			}
5040Sstevel@tonic-gate 		} else {
5050Sstevel@tonic-gate 			/* End of string found */
5060Sstevel@tonic-gate 			done = TRUE;
5070Sstevel@tonic-gate 			leftoff = (char *)NULL;
5080Sstevel@tonic-gate 		}
5090Sstevel@tonic-gate 	} /* while (!done) */
5100Sstevel@tonic-gate 
5110Sstevel@tonic-gate 	/* Finished */
5120Sstevel@tonic-gate 	return (rtnval);
5130Sstevel@tonic-gate }
5140Sstevel@tonic-gate 
5150Sstevel@tonic-gate /*
5160Sstevel@tonic-gate  * void msgverbset()
5170Sstevel@tonic-gate  *
5180Sstevel@tonic-gate  *	Parces the argument of the MSGVERB environment variable and places
5190Sstevel@tonic-gate  *	a representation of the value of that value in "msgverb"
5200Sstevel@tonic-gate  *
5210Sstevel@tonic-gate  * Arguments:
5220Sstevel@tonic-gate  *	None:
5230Sstevel@tonic-gate  *
5240Sstevel@tonic-gate  * Returns: void
5250Sstevel@tonic-gate  *
5260Sstevel@tonic-gate  * Notes:
5270Sstevel@tonic-gate  */
5280Sstevel@tonic-gate 
5290Sstevel@tonic-gate static void
msgverbset(void)5300Sstevel@tonic-gate msgverbset(void)
5310Sstevel@tonic-gate {
5320Sstevel@tonic-gate 	char   *opts;			/* Pointer to MSGVERB's value */
5330Sstevel@tonic-gate 	char   *alloced;		/* Pointer to MSGVERB's value */
5340Sstevel@tonic-gate 	char   *tok;			/* Pointer to current token */
5350Sstevel@tonic-gate 	char   *tokend;			/* Pointer to end of current token */
5360Sstevel@tonic-gate 	char   *nexttok;		/* Pointer to next token */
5370Sstevel@tonic-gate 
5380Sstevel@tonic-gate 
5390Sstevel@tonic-gate 	/* Rid ourselves of junk in "msgverb" */
5400Sstevel@tonic-gate 	msgverb = 0;
5410Sstevel@tonic-gate 
5420Sstevel@tonic-gate 	/* Get the value of MSGVERB.  If none, use default value */
5430Sstevel@tonic-gate 	if ((opts = getenv(MSGVERB)) == (char *)NULL) {
5440Sstevel@tonic-gate 		msgverb = MV_DFLT;
5450Sstevel@tonic-gate 	} else { /* MSGVERB has a value.  Interpret it */
5460Sstevel@tonic-gate 		if ((alloced = libc_malloc(strlen(opts) + 1)) == NULL) {
5470Sstevel@tonic-gate 			msgverb = MV_DFLT;
5480Sstevel@tonic-gate 		} else {
5490Sstevel@tonic-gate 			/* Make a copy of the value of MSGVERB */
5500Sstevel@tonic-gate 			nexttok = strcpy(alloced, opts);
5510Sstevel@tonic-gate 
5520Sstevel@tonic-gate 			/* Parse the options given by the user */
5530Sstevel@tonic-gate 			while ((tok = nexttok) != (char *)NULL) {
5540Sstevel@tonic-gate 				/*
5550Sstevel@tonic-gate 				 * Find end of the next token and squeeze
5560Sstevel@tonic-gate 				 * out escaped characters
5570Sstevel@tonic-gate 				 */
5580Sstevel@tonic-gate 				tokend = exttok(tok, ":");
5590Sstevel@tonic-gate 				tok = noesc(tok);
5600Sstevel@tonic-gate 
5610Sstevel@tonic-gate 				/* Delimit token and mark next, if any */
5620Sstevel@tonic-gate 				if (*tokend == ':') {
5630Sstevel@tonic-gate 					nexttok = tokend + (ptrdiff_t)1;
5640Sstevel@tonic-gate 					*tokend = '\0';
5650Sstevel@tonic-gate 				} else {
5660Sstevel@tonic-gate 					nexttok = (char *)NULL;
5670Sstevel@tonic-gate 				}
5680Sstevel@tonic-gate 
5690Sstevel@tonic-gate 				/* Check for "text" */
5700Sstevel@tonic-gate 				if (strcmp(tok, ST_TXT) == 0) {
5710Sstevel@tonic-gate 					msgverb |= MV_TXT;
5720Sstevel@tonic-gate 
5730Sstevel@tonic-gate 					/* Check for "label" */
5740Sstevel@tonic-gate 				} else if (strcmp(tok, ST_LBL) == 0) {
5750Sstevel@tonic-gate 					msgverb |= MV_LBL;
5760Sstevel@tonic-gate 
5770Sstevel@tonic-gate 					/* Check for "action */
5780Sstevel@tonic-gate 				} else if (strcmp(tok, ST_ACT) == 0) {
5790Sstevel@tonic-gate 					msgverb |= MV_ACT;
5800Sstevel@tonic-gate 
5810Sstevel@tonic-gate 					/* Check for "severity" */
5820Sstevel@tonic-gate 				} else if (strcmp(tok, ST_SEV) == 0) {
5830Sstevel@tonic-gate 					msgverb |= MV_SEV;
5840Sstevel@tonic-gate 
5850Sstevel@tonic-gate 					/* Check for "tag" */
5860Sstevel@tonic-gate 				} else if (strcmp(tok, ST_TAG) == 0) {
5870Sstevel@tonic-gate 					msgverb |= MV_TAG;
5880Sstevel@tonic-gate 
5890Sstevel@tonic-gate 					/* Unknown, ignore MSGVERB value */
5900Sstevel@tonic-gate 				} else {
5910Sstevel@tonic-gate 					msgverb = MV_DFLT;
5920Sstevel@tonic-gate 					nexttok = (char *)NULL;
5930Sstevel@tonic-gate 				}
5940Sstevel@tonic-gate 			} /* do while */
5950Sstevel@tonic-gate 
5960Sstevel@tonic-gate 			/*
5970Sstevel@tonic-gate 			 * Use default if no keywords on MSGVERB
5980Sstevel@tonic-gate 			 * environment variable
5990Sstevel@tonic-gate 			 */
6000Sstevel@tonic-gate 			if (msgverb == 0)
6010Sstevel@tonic-gate 				msgverb = MV_DFLT;
6020Sstevel@tonic-gate 
6030Sstevel@tonic-gate 			/* Free allocated space */
6040Sstevel@tonic-gate 			libc_free(alloced);
6050Sstevel@tonic-gate 		}
6060Sstevel@tonic-gate 	}
6070Sstevel@tonic-gate 	/* Finished */
6080Sstevel@tonic-gate 	/* return; */
6090Sstevel@tonic-gate }
6100Sstevel@tonic-gate 
6110Sstevel@tonic-gate /*
6120Sstevel@tonic-gate  * void sevstrset()
6130Sstevel@tonic-gate  *
6140Sstevel@tonic-gate  *	This function builds a structure containing auxillary severity
6150Sstevel@tonic-gate  *	definitions.
6160Sstevel@tonic-gate  *
6170Sstevel@tonic-gate  *  Arguments:  None
6180Sstevel@tonic-gate  *
6190Sstevel@tonic-gate  *  Returns:  Void
6200Sstevel@tonic-gate  */
6210Sstevel@tonic-gate 
6220Sstevel@tonic-gate static char *sevspace = (char *)NULL;
6230Sstevel@tonic-gate 
6240Sstevel@tonic-gate static void
sevstrset(void)6250Sstevel@tonic-gate sevstrset(void)
6260Sstevel@tonic-gate {
6270Sstevel@tonic-gate 	struct sevstr  *plast;
6280Sstevel@tonic-gate 	struct sevstr  *psev;
6290Sstevel@tonic-gate 	char		*value;
6300Sstevel@tonic-gate 
6310Sstevel@tonic-gate 
6320Sstevel@tonic-gate 	/* Look for SEV_LEVEL definition */
6330Sstevel@tonic-gate 	if ((value = getenv(SEV_LEVEL)) != (char *)NULL) {
6340Sstevel@tonic-gate 
6350Sstevel@tonic-gate 		/* Allocate space and make a copy of the value of SEV_LEVEL */
6360Sstevel@tonic-gate 		if ((sevspace = libc_malloc(strlen(value) + 1)) != NULL) {
6370Sstevel@tonic-gate 			(void) strcpy(sevspace, value);
6380Sstevel@tonic-gate 
6390Sstevel@tonic-gate 			/* Continue for all severity descriptions */
6400Sstevel@tonic-gate 			psev = getauxsevs(sevspace);
6410Sstevel@tonic-gate 			plast = (struct sevstr *)NULL;
6420Sstevel@tonic-gate 			if (psev != (struct sevstr *)NULL) {
6430Sstevel@tonic-gate 				penvsevs = psev;
6440Sstevel@tonic-gate 				plast = psev;
6450Sstevel@tonic-gate 				while (psev = getauxsevs((char *)NULL)) {
6460Sstevel@tonic-gate 					plast->sevnext = psev;
6470Sstevel@tonic-gate 					plast = psev;
6480Sstevel@tonic-gate 				}
6490Sstevel@tonic-gate 			}
6500Sstevel@tonic-gate 		} /* if sevspace != (char *)NULL */
6510Sstevel@tonic-gate 	} /* if value != (char *)NULL */
6520Sstevel@tonic-gate }
6530Sstevel@tonic-gate 
6540Sstevel@tonic-gate /*
6550Sstevel@tonic-gate  * int addseverity(value, string)
6560Sstevel@tonic-gate  *	int	value		Value of the severity
6570Sstevel@tonic-gate  *	const char   *string	Print-string for the severity
6580Sstevel@tonic-gate  *
6590Sstevel@tonic-gate  *  Arguments:
6600Sstevel@tonic-gate  *	value		int
6610Sstevel@tonic-gate  *			The integer value of the severity being added
6620Sstevel@tonic-gate  *	string		char *
6630Sstevel@tonic-gate  *			A pointer to the character-string to be printed
6640Sstevel@tonic-gate  *			whenever a severity of "value" is printed
6650Sstevel@tonic-gate  *
6660Sstevel@tonic-gate  *  Returns:  int
6670Sstevel@tonic-gate  *	Zero if successful, -1 if failed. The function can fail under
6680Sstevel@tonic-gate  *	the following circumstances:
6690Sstevel@tonic-gate  *	  - libc_malloc() fails
6700Sstevel@tonic-gate  *	  - The "value" is one of the reserved values.
6710Sstevel@tonic-gate  *
6720Sstevel@tonic-gate  *	This function permits C applications to define severity-levels
6730Sstevel@tonic-gate  *	that augment the standard levels and those defined by the
6740Sstevel@tonic-gate  *	SEV_LEVEL environment variable.
6750Sstevel@tonic-gate  */
6760Sstevel@tonic-gate 
6770Sstevel@tonic-gate int
addseverity(int value,const char * string)6780Sstevel@tonic-gate addseverity(int value, const char *string)
6790Sstevel@tonic-gate {
6800Sstevel@tonic-gate 	struct sevstr  *p;		/* Temp ptr to severity structs */
6810Sstevel@tonic-gate 	struct sevstr  *q;		/* Temp ptr(follower) to severity */
6820Sstevel@tonic-gate 	int		found;		/* FLAG, element found in the list */
6830Sstevel@tonic-gate 	int		rtnval;		/* Value to return to the caller */
6840Sstevel@tonic-gate 
6850Sstevel@tonic-gate 	/* Make sure we're not trying to redefine one of the reserved values */
6860Sstevel@tonic-gate 	if (value <= 4) {
6870Sstevel@tonic-gate 		errno = EINVAL;
6880Sstevel@tonic-gate 		return (-1);
6890Sstevel@tonic-gate 	}
6900Sstevel@tonic-gate 
6910Sstevel@tonic-gate 	lmutex_lock(&fmt_lock);
6920Sstevel@tonic-gate 
6930Sstevel@tonic-gate 	/* Make sure we've interpreted SEV_LEVEL */
6940Sstevel@tonic-gate 
6950Sstevel@tonic-gate 	if (sevlook) {
6960Sstevel@tonic-gate 		sevstrset();
6970Sstevel@tonic-gate 		sevlook = FALSE;
6980Sstevel@tonic-gate 	}
6990Sstevel@tonic-gate 
7000Sstevel@tonic-gate 
7010Sstevel@tonic-gate 	/*
7020Sstevel@tonic-gate 	 * Leaf through the list.  We may be redefining or removing a
7030Sstevel@tonic-gate 	 * definition
7040Sstevel@tonic-gate 	 */
7050Sstevel@tonic-gate 	q = (struct sevstr *)NULL;
7060Sstevel@tonic-gate 	found = FALSE;
7070Sstevel@tonic-gate 	for (p = paugsevs; !found && (p != (struct sevstr *)NULL);
7080Sstevel@tonic-gate 	    p = p->sevnext) {
7090Sstevel@tonic-gate 		if (p->sevvalue == value) {
7100Sstevel@tonic-gate 			/* We've a match.  Remove or modify the entry */
7110Sstevel@tonic-gate 			if (string == (char *)NULL) {
7120Sstevel@tonic-gate 				if (q == (struct sevstr *)NULL) {
7130Sstevel@tonic-gate 					paugsevs = p->sevnext;
7140Sstevel@tonic-gate 				} else {
7150Sstevel@tonic-gate 					q->sevnext = p->sevnext;
7160Sstevel@tonic-gate 				}
7170Sstevel@tonic-gate 				libc_free(p);
7180Sstevel@tonic-gate 			} else {
7190Sstevel@tonic-gate 				p->sevprstr = string;
7200Sstevel@tonic-gate 			}
7210Sstevel@tonic-gate 			found = TRUE;
7220Sstevel@tonic-gate 		}
7230Sstevel@tonic-gate 		q = p;
7240Sstevel@tonic-gate 	}
7250Sstevel@tonic-gate 
7260Sstevel@tonic-gate 	/* Adding a definition */
7270Sstevel@tonic-gate 	if (!found && (string != (char *)NULL)) {
7280Sstevel@tonic-gate 		/* Allocate space for the severity structure */
7290Sstevel@tonic-gate 		if ((p = libc_malloc(sizeof (struct sevstr))) == NULL) {
7300Sstevel@tonic-gate 			lmutex_unlock(&fmt_lock);
7310Sstevel@tonic-gate 			return (-1);
7320Sstevel@tonic-gate 		}
7330Sstevel@tonic-gate 
7340Sstevel@tonic-gate 		/*
7350Sstevel@tonic-gate 		 * Fill in the new structure with the data supplied and add to
7360Sstevel@tonic-gate 		 * the head of the augmented severity list.
7370Sstevel@tonic-gate 		 */
7380Sstevel@tonic-gate 
7390Sstevel@tonic-gate 		p->sevkywd = (char *)NULL;
7400Sstevel@tonic-gate 		p->sevprstr = string;
7410Sstevel@tonic-gate 		p->sevvalue = value;
7420Sstevel@tonic-gate 		p->sevnext = paugsevs;
7430Sstevel@tonic-gate 		paugsevs = p;
7440Sstevel@tonic-gate 
7450Sstevel@tonic-gate 		/* Successfully added a new severity */
7460Sstevel@tonic-gate 		rtnval = 0;
7470Sstevel@tonic-gate 	} else if (string == (char *)NULL) {
7480Sstevel@tonic-gate 		/* Attempting to undefined a non-defined severity */
7490Sstevel@tonic-gate 		rtnval = -1;
7500Sstevel@tonic-gate 		errno = EINVAL;
7510Sstevel@tonic-gate 	} else {
7520Sstevel@tonic-gate 		/* Successfully redefined a severity */
7530Sstevel@tonic-gate 		rtnval = 0;
7540Sstevel@tonic-gate 	}
7550Sstevel@tonic-gate 	/* Finished, successful */
7560Sstevel@tonic-gate 	lmutex_unlock(&fmt_lock);
7570Sstevel@tonic-gate 	return (rtnval);
7580Sstevel@tonic-gate }
7590Sstevel@tonic-gate 
7600Sstevel@tonic-gate /*
7610Sstevel@tonic-gate  * Utility function for converting an integer to a string, avoiding stdio.
7620Sstevel@tonic-gate  */
7630Sstevel@tonic-gate static void
itoa(int n,char * s)7640Sstevel@tonic-gate itoa(int n, char *s)
7650Sstevel@tonic-gate {
7660Sstevel@tonic-gate 	char buf[12];		/* 32 bits fits in 10 decimal digits */
7670Sstevel@tonic-gate 	char *cp = buf;
7680Sstevel@tonic-gate 	uint_t un = (n < 0)? -n : n;
7690Sstevel@tonic-gate 
7700Sstevel@tonic-gate 	do {
7710Sstevel@tonic-gate 		*cp++ = "0123456789"[un % 10];
7720Sstevel@tonic-gate 		un /= 10;
7730Sstevel@tonic-gate 	} while (un);
7740Sstevel@tonic-gate 
7750Sstevel@tonic-gate 	if (n < 0)
7760Sstevel@tonic-gate 		*s++ = '-';
7770Sstevel@tonic-gate 
7780Sstevel@tonic-gate 	do {
7790Sstevel@tonic-gate 		*s++ = *--cp;
7800Sstevel@tonic-gate 	} while (cp > buf);
7810Sstevel@tonic-gate 
7820Sstevel@tonic-gate 	*s = '\0';
7830Sstevel@tonic-gate }
7840Sstevel@tonic-gate 
7850Sstevel@tonic-gate /*
7860Sstevel@tonic-gate  * void writemsg(buf, size, verbosity, label, severity, text, action, tag)
7870Sstevel@tonic-gate  *
7880Sstevel@tonic-gate  * Arguments:
7890Sstevel@tonic-gate  *	char	*buf		The buffer in which to format the message
7900Sstevel@tonic-gate  *	size_t	size		The size of the buffer
7910Sstevel@tonic-gate  * 	int	verbosity	A bit-string that indicates which components
7920Sstevel@tonic-gate  *				are to be written
7930Sstevel@tonic-gate  * 	const char   *label	The address of the label-component
7940Sstevel@tonic-gate  * 	int	severity	The severity value of the message
7950Sstevel@tonic-gate  * 	const char   *text	The address of the text-component
7960Sstevel@tonic-gate  * 	const char   *action	The address of the action-component
7970Sstevel@tonic-gate  * 	const char   *tag	The address of the tag-component
7980Sstevel@tonic-gate  *
7990Sstevel@tonic-gate  *	This function formats the message consisting of the label-component,
8000Sstevel@tonic-gate  *	severity-component, text-component, action-component, and tag-
8010Sstevel@tonic-gate  *	component into the provided buffer.  The "verbosity" argument
8020Sstevel@tonic-gate  *	tells which components can be selected.  Any or all of the
8030Sstevel@tonic-gate  *	components can be their null-values.
8040Sstevel@tonic-gate  *
8050Sstevel@tonic-gate  * Returns:  void
8060Sstevel@tonic-gate  *
8070Sstevel@tonic-gate  * Notes:
8080Sstevel@tonic-gate  */
8090Sstevel@tonic-gate 
8100Sstevel@tonic-gate static void
writemsg(char * buf,size_t size,int verbosity,const char * label,int severity,const char * text,const char * action,const char * tag)8110Sstevel@tonic-gate writemsg(char *buf, size_t size,
8120Sstevel@tonic-gate 	int verbosity, const char *label, int severity,
8130Sstevel@tonic-gate 	const char *text, const char *action, const char *tag)
8140Sstevel@tonic-gate {
8150Sstevel@tonic-gate 	struct sevstr  *psev;		/* Ptr for severity str list */
8160Sstevel@tonic-gate 	char		*p;		/* General purpose pointer */
8170Sstevel@tonic-gate 	char		*sevpstr = NULL;  /* Pointer to severity string */
8180Sstevel@tonic-gate 	int		l1indent;	/* # chars to indent line 1 */
8190Sstevel@tonic-gate 	int		l2indent;	/* # chars to indent line 2 */
8200Sstevel@tonic-gate 	int		textindent;	/* # spaces to indent text */
8210Sstevel@tonic-gate 	int		actindent = 0;	/* # spaces to indent action */
8220Sstevel@tonic-gate 	int		i;		/* General purpose counter */
8230Sstevel@tonic-gate 	int		dolabel;	/* TRUE if label to be written */
8240Sstevel@tonic-gate 	int		dotext;		/* TRUE if text to be written */
8250Sstevel@tonic-gate 	int		dosev;		/* TRUE if severity to be written */
8260Sstevel@tonic-gate 	int		doaction;	/* TRUE if action to be written */
8270Sstevel@tonic-gate 	int		dotag;		/* TRUE if tag to be written */
8280Sstevel@tonic-gate 	char		c;		/* Temp, multiuse character */
8290Sstevel@tonic-gate 	char		sevpstrbuf[15];	/* Space for SV=%d */
8300Sstevel@tonic-gate 
8310Sstevel@tonic-gate 	char		lcllbl[MM_MXLABELLN+1];	/* Space for (possibly */
8320Sstevel@tonic-gate 						/* truncated) label */
8330Sstevel@tonic-gate 	char		lcltag[MM_MXTAGLN+1];	/* Space for (possibly */
8340Sstevel@tonic-gate 						/* truncated) tag */
8350Sstevel@tonic-gate 	char		*ebuf = buf + size - 2;
8360Sstevel@tonic-gate 
8370Sstevel@tonic-gate 	/*
8380Sstevel@tonic-gate 	 * initialize variables.
8390Sstevel@tonic-gate 	 */
8400Sstevel@tonic-gate 	sevpstrbuf[0] = (char)0;
8410Sstevel@tonic-gate 	lcllbl[0] = (char)0;
8420Sstevel@tonic-gate 	lcltag[0] = (char)0;
8430Sstevel@tonic-gate 
8440Sstevel@tonic-gate 	/*
8450Sstevel@tonic-gate 	 * Figure out what fields are to be written (all are optional)
8460Sstevel@tonic-gate 	 */
8470Sstevel@tonic-gate 
8480Sstevel@tonic-gate 	dolabel  = (verbosity & MV_LBL) && (label != MM_NULLLBL);
8490Sstevel@tonic-gate 	dosev    = (verbosity & MV_SEV) && (severity != MM_NULLSEV);
8500Sstevel@tonic-gate 	dotext   = (verbosity & MV_TXT) && (text != MM_NULLTXT);
8510Sstevel@tonic-gate 	doaction = (verbosity & MV_ACT) && (action != MM_NULLACT);
8520Sstevel@tonic-gate 	dotag    = (verbosity & MV_TAG) && (tag != MM_NULLTAG);
8530Sstevel@tonic-gate 
8540Sstevel@tonic-gate 	/*
8550Sstevel@tonic-gate 	 * Figure out how much we'll need to indent the text of the message
8560Sstevel@tonic-gate 	 */
8570Sstevel@tonic-gate 
8580Sstevel@tonic-gate 	/* Count the label of the message, if requested */
8590Sstevel@tonic-gate 	textindent = 0;
8600Sstevel@tonic-gate 	if (dolabel) {
8610Sstevel@tonic-gate 		(void) strncpy(lcllbl, label, (size_t)MM_MXLABELLN);
8620Sstevel@tonic-gate 		lcllbl[MM_MXLABELLN] = '\0';
8630Sstevel@tonic-gate 		textindent = (int)strlen(lcllbl) + SEPSTRLN;
8640Sstevel@tonic-gate 	}
8650Sstevel@tonic-gate 
8660Sstevel@tonic-gate 	/*
8670Sstevel@tonic-gate 	 * If severity req'd, determine the severity string and factor
8680Sstevel@tonic-gate 	 * into indent count.  Severity string generated by:
8690Sstevel@tonic-gate 	 *	1.  Search the standard list of severities.
8700Sstevel@tonic-gate 	 *	2.  Search the severities added by the application.
8710Sstevel@tonic-gate 	 *	3.  Search the severities added by the environment.
8720Sstevel@tonic-gate 	 *	4.  Use the default (SV=n where n is the value of the severity).
8730Sstevel@tonic-gate 	 */
8740Sstevel@tonic-gate 
8750Sstevel@tonic-gate 	if (dosev) {
8760Sstevel@tonic-gate 		/* Search the default severity definitions */
8770Sstevel@tonic-gate 		psev = pstdsevs;
8780Sstevel@tonic-gate 		while (psev != (struct sevstr *)NULL) {
8790Sstevel@tonic-gate 			if (psev->sevvalue == severity)
8800Sstevel@tonic-gate 				break;
8810Sstevel@tonic-gate 			psev = psev->sevnext;
8820Sstevel@tonic-gate 		}
8830Sstevel@tonic-gate 
8840Sstevel@tonic-gate 		if (psev == (struct sevstr *)NULL) {
8850Sstevel@tonic-gate 			/*
8860Sstevel@tonic-gate 			 * Search the severity definitions
8870Sstevel@tonic-gate 			 * added by the application
8880Sstevel@tonic-gate 			 */
8890Sstevel@tonic-gate 			psev = paugsevs;
8900Sstevel@tonic-gate 			while (psev != (struct sevstr *)NULL) {
8910Sstevel@tonic-gate 				if (psev->sevvalue == severity)
8920Sstevel@tonic-gate 					break;
8930Sstevel@tonic-gate 				psev = psev->sevnext;
8940Sstevel@tonic-gate 			}
8950Sstevel@tonic-gate 			if (psev == (struct sevstr *)NULL) {
8960Sstevel@tonic-gate 				/*
8970Sstevel@tonic-gate 				 * Search the severity definitions
8980Sstevel@tonic-gate 				 * added by the environment
8990Sstevel@tonic-gate 				 */
9000Sstevel@tonic-gate 				psev = penvsevs;
9010Sstevel@tonic-gate 				while (psev != (struct sevstr *)NULL) {
9020Sstevel@tonic-gate 					if (psev->sevvalue == severity)
9030Sstevel@tonic-gate 						break;
9040Sstevel@tonic-gate 					psev = psev->sevnext;
9050Sstevel@tonic-gate 				}
9060Sstevel@tonic-gate 				if (psev == (struct sevstr *)NULL) {
9070Sstevel@tonic-gate 					/* Use default string, SV=severity */
9080Sstevel@tonic-gate 					(void) strcpy(sevpstrbuf, "SV=");
9090Sstevel@tonic-gate 					itoa(severity, &sevpstrbuf[3]);
9100Sstevel@tonic-gate 					sevpstr = sevpstrbuf;
9110Sstevel@tonic-gate 				} else {
9120Sstevel@tonic-gate 					sevpstr = (char *)psev->sevprstr;
9130Sstevel@tonic-gate 				}
9140Sstevel@tonic-gate 			} else {
9150Sstevel@tonic-gate 				sevpstr = (char *)psev->sevprstr;
9160Sstevel@tonic-gate 			}
9170Sstevel@tonic-gate 		} else {
9180Sstevel@tonic-gate 			sevpstr = (char *)psev->sevprstr;
9190Sstevel@tonic-gate 		}
9200Sstevel@tonic-gate 		/* Factor into indent counts */
9210Sstevel@tonic-gate 		textindent += (int)strlen(sevpstr) + SEPSTRLN;
9220Sstevel@tonic-gate 	}
9230Sstevel@tonic-gate 
9240Sstevel@tonic-gate 	/*
9250Sstevel@tonic-gate 	 * Figure out the indents.
9260Sstevel@tonic-gate 	 */
9270Sstevel@tonic-gate 
9280Sstevel@tonic-gate 	if (doaction && dotext) {
9290Sstevel@tonic-gate 		if (textindent > ACTINTROLN) {
9300Sstevel@tonic-gate 			l1indent = 0;
9310Sstevel@tonic-gate 			l2indent = textindent - ACTINTROLN;
9320Sstevel@tonic-gate 			actindent = textindent;
9330Sstevel@tonic-gate 		} else {
9340Sstevel@tonic-gate 			l2indent = 0;
9350Sstevel@tonic-gate 			actindent = ACTINTROLN;
9360Sstevel@tonic-gate 			if (dosev || dolabel) {
9370Sstevel@tonic-gate 				l1indent = ACTINTROLN - textindent;
9380Sstevel@tonic-gate 				textindent = ACTINTROLN;
9390Sstevel@tonic-gate 			} else {
9400Sstevel@tonic-gate 				textindent = 0;
9410Sstevel@tonic-gate 				l1indent = 0;
9420Sstevel@tonic-gate 			}
9430Sstevel@tonic-gate 		}
9440Sstevel@tonic-gate 	} else {
9450Sstevel@tonic-gate 		l1indent = 0;
9460Sstevel@tonic-gate 		l2indent = 0;
9470Sstevel@tonic-gate 		if (doaction) {
9480Sstevel@tonic-gate 			actindent = textindent + ACTINTROLN;
9490Sstevel@tonic-gate 		} else if (dotext) {
9500Sstevel@tonic-gate 			actindent = 0;
9510Sstevel@tonic-gate 		}
9520Sstevel@tonic-gate 	}
9530Sstevel@tonic-gate 
9540Sstevel@tonic-gate 	/*
9550Sstevel@tonic-gate 	 * Write the message.
9560Sstevel@tonic-gate 	 */
9570Sstevel@tonic-gate 
9580Sstevel@tonic-gate 	/* Write the LABEL, if requested */
9590Sstevel@tonic-gate 	if (dolabel) {
9600Sstevel@tonic-gate 		/* Write spaces to align on the ':' char, if needed */
9610Sstevel@tonic-gate 		while (--l1indent >= 0 && buf < ebuf)
9620Sstevel@tonic-gate 			*buf++ = ' ';
9630Sstevel@tonic-gate 
9640Sstevel@tonic-gate 		/* Write the label */
9650Sstevel@tonic-gate 		buf += strlcpy(buf, lcllbl, ebuf - buf);
9660Sstevel@tonic-gate 
9670Sstevel@tonic-gate 		/*
9680Sstevel@tonic-gate 		 * Write the separator string
9690Sstevel@tonic-gate 		 * (if another component is to follow)
9700Sstevel@tonic-gate 		 */
9710Sstevel@tonic-gate 		if (dosev || dotext || doaction || dotag)
9720Sstevel@tonic-gate 			buf += strlcpy(buf, SEPSTR, ebuf - buf);
9730Sstevel@tonic-gate 	}
9740Sstevel@tonic-gate 
9750Sstevel@tonic-gate 	/* Write the SEVERITY, if requested */
9760Sstevel@tonic-gate 	if (dosev) {
9770Sstevel@tonic-gate 		/* Write spaces to align on the ':' char, if needed */
9780Sstevel@tonic-gate 		while (--l1indent >= 0 && buf < ebuf)
9790Sstevel@tonic-gate 			*buf++ = ' ';
9800Sstevel@tonic-gate 
9810Sstevel@tonic-gate 		/* Write the severity print-string */
9820Sstevel@tonic-gate 		buf += strlcpy(buf, sevpstr, ebuf - buf);
9830Sstevel@tonic-gate 
9840Sstevel@tonic-gate 		/*
9850Sstevel@tonic-gate 		 * Write the separator string
9860Sstevel@tonic-gate 		 * (if another component is to follow)
9870Sstevel@tonic-gate 		 */
9880Sstevel@tonic-gate 		if (dotext || doaction || dotag)
9890Sstevel@tonic-gate 			buf += strlcpy(buf, SEPSTR, ebuf - buf);
9900Sstevel@tonic-gate 	}
9910Sstevel@tonic-gate 
9920Sstevel@tonic-gate 	/* Write the TEXT, if requested */
9930Sstevel@tonic-gate 	if (dotext) {
9940Sstevel@tonic-gate 		p = (char *)text;
9950Sstevel@tonic-gate 		for (c = *p++; c != NULL && buf < ebuf; c = *p++) {
9960Sstevel@tonic-gate 			*buf++ = c;
9970Sstevel@tonic-gate 			if (c == '\n') {
9980Sstevel@tonic-gate 				for (i = 0; i < textindent && buf < ebuf; i++)
9990Sstevel@tonic-gate 					*buf++ = ' ';
10000Sstevel@tonic-gate 			}
10010Sstevel@tonic-gate 		}
10020Sstevel@tonic-gate 	}
10030Sstevel@tonic-gate 
10040Sstevel@tonic-gate 	/*
10050Sstevel@tonic-gate 	 * Write ACTION if requested.
10060Sstevel@tonic-gate 	 */
10070Sstevel@tonic-gate 
10080Sstevel@tonic-gate 	if (doaction) {
10090Sstevel@tonic-gate 		if (dotext && buf < ebuf) {
10100Sstevel@tonic-gate 			*buf++ = '\n';
10110Sstevel@tonic-gate 			while (--l2indent >= 0 && buf < ebuf)
10120Sstevel@tonic-gate 				*buf++ = ' ';
10130Sstevel@tonic-gate 		}
10140Sstevel@tonic-gate 
10150Sstevel@tonic-gate 		/* Write the action-string's introduction */
10160Sstevel@tonic-gate 		buf += strlcpy(buf, ACTINTRO, ebuf - buf);
10170Sstevel@tonic-gate 
10180Sstevel@tonic-gate 		/* Write the "action" string */
10190Sstevel@tonic-gate 		p = (char *)action;
10200Sstevel@tonic-gate 		for (c = *p++; c != NULL && buf < ebuf; c = *p++) {
10210Sstevel@tonic-gate 			*buf++ = c;
10220Sstevel@tonic-gate 			if (c == '\n') {
10230Sstevel@tonic-gate 				for (i = 0; i < actindent && buf < ebuf; i++)
10240Sstevel@tonic-gate 					*buf++ = ' ';
10250Sstevel@tonic-gate 			}
10260Sstevel@tonic-gate 		}
10270Sstevel@tonic-gate 	}
10280Sstevel@tonic-gate 
10290Sstevel@tonic-gate 	/*
10300Sstevel@tonic-gate 	 * Write the TAG if requested
10310Sstevel@tonic-gate 	 */
10320Sstevel@tonic-gate 
10330Sstevel@tonic-gate 	if (dotag) {
10340Sstevel@tonic-gate 		if (doaction)
10350Sstevel@tonic-gate 			buf += strlcpy(buf, "  ", ebuf - buf);
10360Sstevel@tonic-gate 		else if (dotext && buf < ebuf)
10370Sstevel@tonic-gate 			*buf++ = '\n';
10380Sstevel@tonic-gate 		(void) strncpy(lcltag, tag, (size_t)MM_MXTAGLN);
10390Sstevel@tonic-gate 		lcltag[MM_MXTAGLN] = '\0';
10400Sstevel@tonic-gate 		buf += strlcpy(buf, lcltag, ebuf - buf);
10410Sstevel@tonic-gate 	}
10420Sstevel@tonic-gate 
10430Sstevel@tonic-gate 	/*
10440Sstevel@tonic-gate 	 * Write terminating newline and null byte.
10450Sstevel@tonic-gate 	 * We reserved space for these at the start.
10460Sstevel@tonic-gate 	 */
10470Sstevel@tonic-gate 	*buf++ = '\n';
10480Sstevel@tonic-gate 	*buf++ = '\0';
10490Sstevel@tonic-gate }
10500Sstevel@tonic-gate 
10510Sstevel@tonic-gate /*
10520Sstevel@tonic-gate  * int	fmtmsg(class, label, severity, text, action, tag)
10530Sstevel@tonic-gate  *	long	class
10540Sstevel@tonic-gate  *	const char   *label
10550Sstevel@tonic-gate  *	int	severity
10560Sstevel@tonic-gate  *	const char   *text
10570Sstevel@tonic-gate  *	const char   *action
10580Sstevel@tonic-gate  *	const char   *tag
10590Sstevel@tonic-gate  *
10600Sstevel@tonic-gate  *	If requested, the fmtmsg() function writes a message to the standard
10610Sstevel@tonic-gate  *      error stream in the standard message format.  Also if requested, it
10620Sstevel@tonic-gate  *	will write a message to the system console.
10630Sstevel@tonic-gate  *
10640Sstevel@tonic-gate  *	Arguments:
10650Sstevel@tonic-gate  *	    class	Fields which classify the message for the system
10660Sstevel@tonic-gate  *			logging facility
10670Sstevel@tonic-gate  *	    label	A character-string that is printed as the "label"
10680Sstevel@tonic-gate  *			of the message.  Typically identifies the source
10690Sstevel@tonic-gate  *			of the message
10700Sstevel@tonic-gate  *	    severity	Identifies the severity of the message.  Either one
10710Sstevel@tonic-gate  *			of the standard severities, or possibly one of the
10720Sstevel@tonic-gate  *			augmented severities
10730Sstevel@tonic-gate  *	    text	Pointer to the text of the message
10740Sstevel@tonic-gate  *	    action	Pointer to a char string that describes some type
10750Sstevel@tonic-gate  *			of corrective action.
10760Sstevel@tonic-gate  *	    tag		A character-string that is printed as the "tag" or
10770Sstevel@tonic-gate  *			the message.  Typically a pointer to documentation
10780Sstevel@tonic-gate  *
10790Sstevel@tonic-gate  *	Returns:
10800Sstevel@tonic-gate  *	    -1 if nothing was generated, 0 if everything requested was
10810Sstevel@tonic-gate  *	    generated, or flags if partially generated.
10820Sstevel@tonic-gate  *
10830Sstevel@tonic-gate  *	Needs:
10840Sstevel@tonic-gate  *	  - Nothing special for 4.0.
10850Sstevel@tonic-gate  */
10860Sstevel@tonic-gate 
10870Sstevel@tonic-gate int
fmtmsg(long class,const char * label,int severity,const char * text,const char * action,const char * tag)10880Sstevel@tonic-gate fmtmsg(long class, const char *label, int severity,
10890Sstevel@tonic-gate const char *text, const char *action, const char *tag)
10900Sstevel@tonic-gate {
10910Sstevel@tonic-gate 	int	rtnval;		/* Value to return */
10920Sstevel@tonic-gate 	FILE	*console;	/* Ptr to "console" stream */
10930Sstevel@tonic-gate 	char	*message1;
10940Sstevel@tonic-gate 	char	*message2;
10950Sstevel@tonic-gate 
10960Sstevel@tonic-gate 	/*
10970Sstevel@tonic-gate 	 * Determine the "verbosity" of the message.  If "msgverb" is
10980Sstevel@tonic-gate 	 * already set, don't interrogate the "MSGVERB" environment vbl.
10990Sstevel@tonic-gate 	 * If so, interrogate "MSGVERB" and do initialization stuff also.
11000Sstevel@tonic-gate 	 */
11010Sstevel@tonic-gate 
11020Sstevel@tonic-gate 	lmutex_lock(&fmt_lock);
11030Sstevel@tonic-gate 
11040Sstevel@tonic-gate 	if (!(msgverb & MV_SET)) {
11050Sstevel@tonic-gate 		msgverbset();
11060Sstevel@tonic-gate 		msgverb |= MV_SET;
11070Sstevel@tonic-gate 	}
11080Sstevel@tonic-gate 
11090Sstevel@tonic-gate 
11100Sstevel@tonic-gate 	/*
11110Sstevel@tonic-gate 	 * Extract the severity definitions from the SEV_LEVEL
11120Sstevel@tonic-gate 	 * environment variable and save away for later.
11130Sstevel@tonic-gate 	 */
11140Sstevel@tonic-gate 
11150Sstevel@tonic-gate 	if (sevlook) {
11160Sstevel@tonic-gate 		sevstrset();
11170Sstevel@tonic-gate 		sevlook = FALSE;
11180Sstevel@tonic-gate 	}
11190Sstevel@tonic-gate 
11200Sstevel@tonic-gate 
11210Sstevel@tonic-gate 	/* Set up the default text component [if text==(char *)NULL] */
11220Sstevel@tonic-gate 	if (text == (char *)NULL)
11230Sstevel@tonic-gate 		text = DEFLT_TEXT;
11240Sstevel@tonic-gate 
11250Sstevel@tonic-gate 	/* Prepare the message for stderr if requested */
11260Sstevel@tonic-gate 	if (class & MM_PRINT) {
11270Sstevel@tonic-gate 		message1 = alloca(MAX_MSG_SIZE);
11280Sstevel@tonic-gate 		writemsg(message1, MAX_MSG_SIZE,
11290Sstevel@tonic-gate 		    msgverb, label, severity, text, action, tag);
11300Sstevel@tonic-gate 	}
11310Sstevel@tonic-gate 
11320Sstevel@tonic-gate 	/* Prepare the message for the console if requested */
11330Sstevel@tonic-gate 	if (class & MM_CONSOLE) {
11340Sstevel@tonic-gate 		message2 = alloca(MAX_MSG_SIZE);
11350Sstevel@tonic-gate 		writemsg(message2, MAX_MSG_SIZE,
11360Sstevel@tonic-gate 		    MV_ALL, label, severity, text, action, tag);
11370Sstevel@tonic-gate 	}
11380Sstevel@tonic-gate 
11390Sstevel@tonic-gate 	lmutex_unlock(&fmt_lock);
11400Sstevel@tonic-gate 
11410Sstevel@tonic-gate 	rtnval = MM_OK;
11420Sstevel@tonic-gate 
11430Sstevel@tonic-gate 	/* Write the message to stderr if requested */
11440Sstevel@tonic-gate 	if (class & MM_PRINT) {
11450Sstevel@tonic-gate 		clearerr(stderr);
11460Sstevel@tonic-gate 		(void) fputs(message1, stderr);
11470Sstevel@tonic-gate 		if (ferror(stderr))
11480Sstevel@tonic-gate 			rtnval |= MM_NOMSG;
11490Sstevel@tonic-gate 	}
11500Sstevel@tonic-gate 
11510Sstevel@tonic-gate 	/* Write the message to the console if requested */
11520Sstevel@tonic-gate 	if (class & MM_CONSOLE) {
11531914Scasper 		if ((console = fopen(CONNAME, "wF")) != NULL) {
11540Sstevel@tonic-gate 			clearerr(console);
11550Sstevel@tonic-gate 			(void) fputs(message2, console);
11560Sstevel@tonic-gate 			if (ferror(console))
11570Sstevel@tonic-gate 				rtnval |= MM_NOCON;
11580Sstevel@tonic-gate 			(void) fclose(console);
11590Sstevel@tonic-gate 		} else {
11600Sstevel@tonic-gate 			rtnval |= MM_NOCON;
11610Sstevel@tonic-gate 		}
11620Sstevel@tonic-gate 	}
11630Sstevel@tonic-gate 
11640Sstevel@tonic-gate 	if ((rtnval & (MM_NOCON | MM_NOMSG)) == (MM_NOCON | MM_NOMSG))
11650Sstevel@tonic-gate 		rtnval = MM_NOTOK;
11660Sstevel@tonic-gate 	return (rtnval);
11670Sstevel@tonic-gate }
1168