xref: /onnv-gate/usr/src/cmd/fmtmsg/main.c (revision 335:d26e4323ca82)
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
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate 
230Sstevel@tonic-gate /*
240Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
250Sstevel@tonic-gate  * Use is subject to license terms.
260Sstevel@tonic-gate  */
270Sstevel@tonic-gate 
28*335Smuffin /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
29*335Smuffin /*	  All Rights Reserved  	*/
30*335Smuffin 
310Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
320Sstevel@tonic-gate 
330Sstevel@tonic-gate 
340Sstevel@tonic-gate /*
350Sstevel@tonic-gate  * fmtmsg.c
360Sstevel@tonic-gate  *
370Sstevel@tonic-gate  * Contains:
380Sstevel@tonic-gate  *	fmtmsg		Command that writes a message in the standard
390Sstevel@tonic-gate  *			message format.  May in future make these
400Sstevel@tonic-gate  *			messages available for logging.
410Sstevel@tonic-gate  */
420Sstevel@tonic-gate 
430Sstevel@tonic-gate 
440Sstevel@tonic-gate /*
450Sstevel@tonic-gate  * Header files used:
460Sstevel@tonic-gate  *	<stdio.h>	C Standard I/O function definitions
470Sstevel@tonic-gate  *	<string.h>	C string-handling definitions
480Sstevel@tonic-gate  *	<errno.h>	UNIX error-code "errno" definitions
490Sstevel@tonic-gate  *	<fmtmsg.h>	Standard Message definitions
500Sstevel@tonic-gate  */
510Sstevel@tonic-gate 
520Sstevel@tonic-gate #include	<stdio.h>
530Sstevel@tonic-gate #include	<string.h>
540Sstevel@tonic-gate #include	<errno.h>
550Sstevel@tonic-gate #include	<fmtmsg.h>
560Sstevel@tonic-gate 
570Sstevel@tonic-gate 
580Sstevel@tonic-gate /*
590Sstevel@tonic-gate  * Externals referenced:
600Sstevel@tonic-gate  *	strtol		Function that converts char strings to "long"
610Sstevel@tonic-gate  *	fmtmsg		Function that writes a message in standard format
620Sstevel@tonic-gate  *	getenv		Function that extracts an environment variable's
630Sstevel@tonic-gate  *			value
640Sstevel@tonic-gate  *	malloc		Allocate memory from the memory pool
650Sstevel@tonic-gate  *	free		Frees allocated memory
660Sstevel@tonic-gate  *	getopt		Function that extracts arguments from the command-
670Sstevel@tonic-gate  *	optarg		Points to option's argument (from getopt())
680Sstevel@tonic-gate  *	optind		Option's argument index (from getopt())
690Sstevel@tonic-gate  *	opterr		FLAG, write error if invalid option (for getopt())
700Sstevel@tonic-gate  *			line.
710Sstevel@tonic-gate  *	exit		Exits the command
720Sstevel@tonic-gate  */
730Sstevel@tonic-gate 
740Sstevel@tonic-gate extern	long		strtol();
750Sstevel@tonic-gate extern	int		fmtmsg();
760Sstevel@tonic-gate extern	char	       *getenv();
770Sstevel@tonic-gate extern	void	       *malloc();
780Sstevel@tonic-gate extern	void		free();
790Sstevel@tonic-gate extern	int		getopt();
800Sstevel@tonic-gate extern	char	       *optarg;
810Sstevel@tonic-gate extern	int		optind;
820Sstevel@tonic-gate extern	int		opterr;
830Sstevel@tonic-gate extern	void		exit();
840Sstevel@tonic-gate 
850Sstevel@tonic-gate /*
860Sstevel@tonic-gate  * Local definitions
870Sstevel@tonic-gate  */
880Sstevel@tonic-gate 
890Sstevel@tonic-gate /*
900Sstevel@tonic-gate  * Local constants
910Sstevel@tonic-gate  */
920Sstevel@tonic-gate 
930Sstevel@tonic-gate 
940Sstevel@tonic-gate /*
950Sstevel@tonic-gate  * Boolean constants
960Sstevel@tonic-gate  *	TRUE	Boolean value for "true" (any bits on)
970Sstevel@tonic-gate  *	FALSE	Boolean value for "false" (all bits off)
980Sstevel@tonic-gate  */
990Sstevel@tonic-gate 
1000Sstevel@tonic-gate #ifndef	FALSE
1010Sstevel@tonic-gate #define	FALSE		(0)
1020Sstevel@tonic-gate #endif
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate #ifndef TRUE
1050Sstevel@tonic-gate #define	TRUE		(1)
1060Sstevel@tonic-gate #endif
1070Sstevel@tonic-gate 
1080Sstevel@tonic-gate 
1090Sstevel@tonic-gate #define	CLASS		(MM_PRINT|MM_SOFT|MM_NRECOV|MM_UTIL)
1100Sstevel@tonic-gate #define BIGUSAGE	"fmtmsg [-a action] [-c class] [-l label] [-s severity] [-t tag]\n       [-u subclass[,subclass[,...]]] [text]\n"
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate 
1130Sstevel@tonic-gate /*
1140Sstevel@tonic-gate  * Local data-type definitions
1150Sstevel@tonic-gate  */
1160Sstevel@tonic-gate 
1170Sstevel@tonic-gate /*
1180Sstevel@tonic-gate  * Structure used for tables containing keywords and integer values
1190Sstevel@tonic-gate  */
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate struct sev_info {
1220Sstevel@tonic-gate 	char   *keyword;
1230Sstevel@tonic-gate 	int	value;
1240Sstevel@tonic-gate };
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate 
1270Sstevel@tonic-gate /*
1280Sstevel@tonic-gate  * Structure used for tables containing keywords, long values
1290Sstevel@tonic-gate  */
1300Sstevel@tonic-gate 
1310Sstevel@tonic-gate struct class_info {
1320Sstevel@tonic-gate 	char   *keyword;
1330Sstevel@tonic-gate 	long	value;
1340Sstevel@tonic-gate 	long	conflict;
1350Sstevel@tonic-gate };
1360Sstevel@tonic-gate 
1370Sstevel@tonic-gate 
1380Sstevel@tonic-gate /*
1390Sstevel@tonic-gate  * Severity string structure
1400Sstevel@tonic-gate  *
1410Sstevel@tonic-gate  *	struct sevstr
1420Sstevel@tonic-gate  *		sevvalue	Value of the severity-level being defined
1430Sstevel@tonic-gate  *		sevkywd		Keyword identifying the severity
1440Sstevel@tonic-gate  *		sevprptr	Pointer to the string associated with the value
1450Sstevel@tonic-gate  *		sevnext		Pointer to the next value in the list.
1460Sstevel@tonic-gate  */
1470Sstevel@tonic-gate 
1480Sstevel@tonic-gate struct sevstr {
1490Sstevel@tonic-gate 	int		sevvalue;
1500Sstevel@tonic-gate 	char           *sevkywd;
1510Sstevel@tonic-gate 	char	       *sevprstr;
1520Sstevel@tonic-gate 	struct sevstr  *sevnext;
1530Sstevel@tonic-gate };
1540Sstevel@tonic-gate 
1550Sstevel@tonic-gate 
1560Sstevel@tonic-gate /*
1570Sstevel@tonic-gate  * Local static data
1580Sstevel@tonic-gate  */
1590Sstevel@tonic-gate 
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate /*
1620Sstevel@tonic-gate  * Table contains the keywords for the classes of a message
1630Sstevel@tonic-gate  */
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate static	struct class_info	classes[] = {
1660Sstevel@tonic-gate 
1670Sstevel@tonic-gate 	{"hard", 	MM_HARD,	MM_SOFT|MM_FIRM},	/* hardware */
1680Sstevel@tonic-gate 	{"soft", 	MM_SOFT,	MM_HARD|MM_FIRM},	/* software */
1690Sstevel@tonic-gate 	{"firm", 	MM_FIRM,	MM_SOFT|MM_FIRM},	/* firmware */
1700Sstevel@tonic-gate 
1710Sstevel@tonic-gate 	{(char *) NULL,	0L,		0L}			/* end of list */
1720Sstevel@tonic-gate 
1730Sstevel@tonic-gate };
1740Sstevel@tonic-gate 
1750Sstevel@tonic-gate 
1760Sstevel@tonic-gate /*
1770Sstevel@tonic-gate  * Table contains the keywords for the subclasses for a message
1780Sstevel@tonic-gate  */
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate static	struct class_info	subclasses[] = 	{
1810Sstevel@tonic-gate 
1820Sstevel@tonic-gate 	{"appl",     	MM_APPL,	MM_UTIL|MM_OPSYS},	/* Application */
1830Sstevel@tonic-gate 	{"util",     	MM_UTIL,	MM_APPL|MM_OPSYS},	/* Utility */
1840Sstevel@tonic-gate 	{"opsys",    	MM_OPSYS,	MM_APPL|MM_UTIL},	/* Operating System */
1850Sstevel@tonic-gate 
1860Sstevel@tonic-gate 	{"recov",    	MM_RECOVER,	MM_NRECOV},		/* Recoverable */
1870Sstevel@tonic-gate 	{"nrecov",   	MM_NRECOV,	MM_RECOVER},		/* Non-recoverable */
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate 	{"print",    	MM_PRINT,	0L}, 			/* Write message to stderr */
1900Sstevel@tonic-gate 	{"console",  	MM_CONSOLE,	0L},			/* Write message on /dev/console */
1910Sstevel@tonic-gate 	{(char *) NULL,	0L,		0L}			/* End of list */
1920Sstevel@tonic-gate 
1930Sstevel@tonic-gate };
1940Sstevel@tonic-gate 
1950Sstevel@tonic-gate 
1960Sstevel@tonic-gate /*
1970Sstevel@tonic-gate  * Table contains the keywords for the standard severities of a message.
1980Sstevel@tonic-gate  * User may supply more through the SEV_LEVEL environment variable.
1990Sstevel@tonic-gate  */
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate static  struct sev_info		severities[] =  {
2020Sstevel@tonic-gate 	{"halt",	MM_HALT},	/* halt */
2030Sstevel@tonic-gate 	{"error",	MM_ERROR},	/* error */
2040Sstevel@tonic-gate 	{"warn",	MM_WARNING},	/* warn */
2050Sstevel@tonic-gate 	{"info",	MM_INFO},	/* info */
2060Sstevel@tonic-gate 	{(char *) NULL,	0}		/* end of list */
2070Sstevel@tonic-gate };
2080Sstevel@tonic-gate 
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate /*
2110Sstevel@tonic-gate  * Buffers used by the command
2120Sstevel@tonic-gate  */
2130Sstevel@tonic-gate 
2140Sstevel@tonic-gate static	char	labelbuf[128];		/* Buf for message label */
2150Sstevel@tonic-gate static	char	msgbuf[256];		/* Buf for messages */
2160Sstevel@tonic-gate 
2170Sstevel@tonic-gate /*
2180Sstevel@tonic-gate  * static char *exttok(str, delims)
2190Sstevel@tonic-gate  *	char   *str
2200Sstevel@tonic-gate  *	char   *delims
2210Sstevel@tonic-gate  *
2220Sstevel@tonic-gate  *	This function examines the string pointed to by "str", looking
2230Sstevel@tonic-gate  *	for the first occurrence of any of the characters in the string
2240Sstevel@tonic-gate  *	whose address is "delims".  It returns the address of that
2250Sstevel@tonic-gate  *	character or (char *) NULL if there was nothing to search.
2260Sstevel@tonic-gate  *
2270Sstevel@tonic-gate  * Arguments:
2280Sstevel@tonic-gate  *	str	Address of the string to search
2290Sstevel@tonic-gate  *	delims	Address of the string containing delimiters
2300Sstevel@tonic-gate  *
2310Sstevel@tonic-gate  * Returns:  char *
2320Sstevel@tonic-gate  *	Returns the address of the first occurrence of any of the characters
2330Sstevel@tonic-gate  *	in "delim" in the string "str" (incl '\0').  If there was nothing
2340Sstevel@tonic-gate  *	to search, the function returns (char *) NULL.
2350Sstevel@tonic-gate  *
2360Sstevel@tonic-gate  * Notes:
2370Sstevel@tonic-gate  *    - This function is needed because strtok() can't be used inside a
2380Sstevel@tonic-gate  *	function.  Besides, strtok() is destructive in the string, which
2390Sstevel@tonic-gate  *	is undesirable in many circumstances.
2400Sstevel@tonic-gate  *    - This function understands escaped delimiters as non-delimiters.
2410Sstevel@tonic-gate  *	Delimiters are escaped by preceding them with '\' characters.
2420Sstevel@tonic-gate  *	The '\' character also must be escaped.
2430Sstevel@tonic-gate  */
2440Sstevel@tonic-gate 
2450Sstevel@tonic-gate static char *
exttok(tok,delims)2460Sstevel@tonic-gate exttok(tok, delims)
2470Sstevel@tonic-gate 	char   *tok;		/* Ptr to the token we're parsing */
2480Sstevel@tonic-gate 	char   *delims;		/* Ptr to string with delimiters */
2490Sstevel@tonic-gate {
2500Sstevel@tonic-gate 
2510Sstevel@tonic-gate 	/* Automatic Data */
2520Sstevel@tonic-gate 	char   *tokend;		/* Ptr to the end of the token */
2530Sstevel@tonic-gate 	char   *p, *q;	 	/* Temp pointers */
2540Sstevel@tonic-gate 
2550Sstevel@tonic-gate 
2560Sstevel@tonic-gate 	/* Algorithm:
2570Sstevel@tonic-gate 	 *    1.  Get the starting address (new string or where we
2580Sstevel@tonic-gate 	 *	  left off).  If nothing to search, return (char *) NULL
2590Sstevel@tonic-gate 	 *    2.  Find the end of the string
2600Sstevel@tonic-gate 	 *    3.  Look for the first unescaped delimiter closest to the
2610Sstevel@tonic-gate 	 *	  beginning of the string
2620Sstevel@tonic-gate 	 *    4.  Remember where we left off
2630Sstevel@tonic-gate 	 *    5.  Return a pointer to the delimiter we found
2640Sstevel@tonic-gate 	 */
2650Sstevel@tonic-gate 
2660Sstevel@tonic-gate 	/* Begin at the beginning, if any */
2670Sstevel@tonic-gate 	if (tok == (char *) NULL) {
2680Sstevel@tonic-gate 	    return ((char *) NULL);
2690Sstevel@tonic-gate 	}
2700Sstevel@tonic-gate 
2710Sstevel@tonic-gate 	/* Find end of the token string */
2720Sstevel@tonic-gate 	tokend = tok + strlen(tok);
2730Sstevel@tonic-gate 
2740Sstevel@tonic-gate 	/* Look for the 1st occurrence of any delimiter */
2750Sstevel@tonic-gate 	for (p = delims ; *p != '\0' ; p++) {
2760Sstevel@tonic-gate 	    for (q = strchr(tok, *p) ; q && (q != tok) && (*(q-1) == '\\') ; q = strchr(q+1, *p)) ;
2770Sstevel@tonic-gate 	    if (q && (q < tokend)) tokend = q;
2780Sstevel@tonic-gate 	}
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate 	/* Done */
2810Sstevel@tonic-gate 	return(tokend);
2820Sstevel@tonic-gate }
2830Sstevel@tonic-gate 
2840Sstevel@tonic-gate /*
2850Sstevel@tonic-gate  * char *noesc(str)
2860Sstevel@tonic-gate  *
2870Sstevel@tonic-gate  *	This function squeezes out all of the escaped character sequences
2880Sstevel@tonic-gate  *	from the string <str>.  It returns a pointer to that string.
2890Sstevel@tonic-gate  *
2900Sstevel@tonic-gate  *  Arguments:
2910Sstevel@tonic-gate  *	str	char *
2920Sstevel@tonic-gate  *		The string that is to have its escaped characters removed.
2930Sstevel@tonic-gate  *
2940Sstevel@tonic-gate  *  Returns:  char *
2950Sstevel@tonic-gate  *	This function returns its argument <str> always.
2960Sstevel@tonic-gate  *
2970Sstevel@tonic-gate  *  Notes:
2980Sstevel@tonic-gate  *	This function potentially modifies the string it is given.
2990Sstevel@tonic-gate  */
3000Sstevel@tonic-gate 
3010Sstevel@tonic-gate char *
noesc(str)3020Sstevel@tonic-gate noesc(str)
3030Sstevel@tonic-gate 	char   *str;		/* String to remove escaped characters from */
3040Sstevel@tonic-gate {
3050Sstevel@tonic-gate 	char   *p;		/* Temp string pointer */
3060Sstevel@tonic-gate 	char   *q;		/* Temp string pointer */
3070Sstevel@tonic-gate 
3080Sstevel@tonic-gate 	/* Look for an escaped character */
3090Sstevel@tonic-gate 	p = str;
3100Sstevel@tonic-gate 	while (*p && (*p != '\\')) p++;
3110Sstevel@tonic-gate 
3120Sstevel@tonic-gate 
3130Sstevel@tonic-gate 	/*
3140Sstevel@tonic-gate 	 * If there was at least one, squeeze them out
3150Sstevel@tonic-gate 	 * Otherwise, don't touch the argument string
3160Sstevel@tonic-gate 	 */
3170Sstevel@tonic-gate 
3180Sstevel@tonic-gate 	if (*p) {
3190Sstevel@tonic-gate 	    q = p++;
3200Sstevel@tonic-gate 	    while (*q++ = *p++) if (*p == '\\') p++;
3210Sstevel@tonic-gate 	}
3220Sstevel@tonic-gate 
3230Sstevel@tonic-gate 	/* Finished.  Return our argument */
3240Sstevel@tonic-gate 	return(str);
3250Sstevel@tonic-gate }
3260Sstevel@tonic-gate 
3270Sstevel@tonic-gate /*
3280Sstevel@tonic-gate  * struct sevstr *getauxsevs(ptr)
3290Sstevel@tonic-gate  *
3300Sstevel@tonic-gate  *	Parses a string that is in the format of the severity definitions.
3310Sstevel@tonic-gate  *	Returns a pointer to a (malloc'd) structure that contains the
3320Sstevel@tonic-gate  *	definition, or (struct sevstr *) NULL if none was parsed.
3330Sstevel@tonic-gate  *
3340Sstevel@tonic-gate  * Arguments:
3350Sstevel@tonic-gate  *	ptr	char *
3360Sstevel@tonic-gate  *		References the string from which data is to be extracted.
3370Sstevel@tonic-gate  *		If (char *) NULL, continue where we left off.  Otherwise,
3380Sstevel@tonic-gate  *		start with the string referenced by ptr.
3390Sstevel@tonic-gate  *
3400Sstevel@tonic-gate  * Returns: struct sevstr *
3410Sstevel@tonic-gate  *	A pointer to a malloc'd structure containing the severity definition
3420Sstevel@tonic-gate  *	parsed from string, or (struct sevstr *) NULL if none.
3430Sstevel@tonic-gate  *
3440Sstevel@tonic-gate  * Notes:
3450Sstevel@tonic-gate  *    - This function is destructive to the string referenced by its argument.
3460Sstevel@tonic-gate  */
3470Sstevel@tonic-gate 
3480Sstevel@tonic-gate 
3490Sstevel@tonic-gate /* Static data */
3500Sstevel@tonic-gate static	char	       *leftoff = (char *) NULL;
3510Sstevel@tonic-gate 
3520Sstevel@tonic-gate static	struct sevstr *
getauxsevs(ptr)3530Sstevel@tonic-gate getauxsevs(ptr)
3540Sstevel@tonic-gate 	char   *ptr;
3550Sstevel@tonic-gate {
3560Sstevel@tonic-gate 
3570Sstevel@tonic-gate 	/* Automatic data */
3580Sstevel@tonic-gate 	char	       *current;	/* Ptr to current sev def'n */
3590Sstevel@tonic-gate 	char	       *tokend;		/* Ptr to end of current sev def'n */
3600Sstevel@tonic-gate 	char	       *kywd;		/* Ptr to extracted kywd */
3610Sstevel@tonic-gate 	char	       *valstr;		/* Ptr to extracted sev value */
3620Sstevel@tonic-gate 	char	       *prstr;		/* Ptr to extracted print str */
3630Sstevel@tonic-gate 	char	       *p;		/* Temp pointer */
3640Sstevel@tonic-gate 	int		val;		/* Converted severity value */
3650Sstevel@tonic-gate 	int		done;		/* Flag, sev def'n found and ok? */
3660Sstevel@tonic-gate 	struct sevstr  *rtnval;		/* Value to return */
3670Sstevel@tonic-gate 
3680Sstevel@tonic-gate 
3690Sstevel@tonic-gate 	/* Start anew or start where we left off? */
3700Sstevel@tonic-gate 	current = (ptr == (char *) NULL) ? leftoff : ptr;
3710Sstevel@tonic-gate 
3720Sstevel@tonic-gate 
3730Sstevel@tonic-gate 	/* If nothing to parse, return (char *) NULL */
3740Sstevel@tonic-gate 	if (current == (char *) NULL) {
3750Sstevel@tonic-gate 	    return ((struct sevstr *) NULL);
3760Sstevel@tonic-gate 	}
3770Sstevel@tonic-gate 
3780Sstevel@tonic-gate 
3790Sstevel@tonic-gate 	/*
3800Sstevel@tonic-gate 	 * Look through the string "current" for a token of the form
3810Sstevel@tonic-gate 	 * <kywd>,<sev>,<printstring> delimited by ':' or '\0'
3820Sstevel@tonic-gate 	 */
3830Sstevel@tonic-gate 
3840Sstevel@tonic-gate 	/* Loop initializations */
3850Sstevel@tonic-gate 	done = FALSE;
3860Sstevel@tonic-gate 	rtnval = (struct sevstr *) NULL;
3870Sstevel@tonic-gate 	while (!done) {
3880Sstevel@tonic-gate 
3890Sstevel@tonic-gate 	    /* Eat leading junk */
3900Sstevel@tonic-gate 	    while (*(tokend = exttok(current, ":,")) == ':') {
3910Sstevel@tonic-gate 		current = tokend + 1;
3920Sstevel@tonic-gate 	    }
3930Sstevel@tonic-gate 
3940Sstevel@tonic-gate 	    /* If we've found a <kywd>,... */
3950Sstevel@tonic-gate 	    if (*tokend == ',') {
3960Sstevel@tonic-gate 		kywd = current;
3970Sstevel@tonic-gate 		*tokend = '\0';
3980Sstevel@tonic-gate 
3990Sstevel@tonic-gate 		/* Look for <kywd>,<sev>,... */
4000Sstevel@tonic-gate 		current = tokend + 1;
4010Sstevel@tonic-gate 		if (*(tokend = exttok(current, ":,")) == ',') {
4020Sstevel@tonic-gate 		    valstr = current;
4030Sstevel@tonic-gate 		    *tokend = '\0';
4040Sstevel@tonic-gate 		    current = tokend+1;
4050Sstevel@tonic-gate 		    prstr = current;
4060Sstevel@tonic-gate 
4070Sstevel@tonic-gate 		    /* Make sure <sev> > 4 */
4080Sstevel@tonic-gate 		    val = (int) strtol(noesc(valstr), &p, 0);
4090Sstevel@tonic-gate 		    if ((val > 4) && (p == tokend)) {
4100Sstevel@tonic-gate 
4110Sstevel@tonic-gate 			/*
4120Sstevel@tonic-gate 			 * Found <kywd>,<sev>,<printstring>.
4130Sstevel@tonic-gate 			 * remember where we left off
4140Sstevel@tonic-gate 			 */
4150Sstevel@tonic-gate 
4160Sstevel@tonic-gate 		        if (*(tokend = exttok(current, ":")) == ':') {
4170Sstevel@tonic-gate 			    *tokend = '\0';
4180Sstevel@tonic-gate 			    leftoff = tokend + 1;
4190Sstevel@tonic-gate 			} else leftoff = (char *) NULL;
4200Sstevel@tonic-gate 
4210Sstevel@tonic-gate 			/* Alloc structure to contain severity definition */
4220Sstevel@tonic-gate 			if (rtnval = (struct sevstr *) malloc(sizeof(struct sevstr))) {
4230Sstevel@tonic-gate 
4240Sstevel@tonic-gate 			    /* Fill in structure */
4250Sstevel@tonic-gate 			    rtnval->sevkywd = noesc(kywd);
4260Sstevel@tonic-gate 			    rtnval->sevvalue = val;
4270Sstevel@tonic-gate 			    rtnval->sevprstr = noesc(prstr);
4280Sstevel@tonic-gate 			    rtnval->sevnext = (struct sevstr *) NULL;
4290Sstevel@tonic-gate 			}
4300Sstevel@tonic-gate 
4310Sstevel@tonic-gate 			done = TRUE;
4320Sstevel@tonic-gate 
4330Sstevel@tonic-gate 		    } else {
4340Sstevel@tonic-gate 
4350Sstevel@tonic-gate 			/* Invalid severity value, eat thru end of token */
4360Sstevel@tonic-gate 			current = tokend;
4370Sstevel@tonic-gate 			if (*(tokend = exttok(prstr, ":")) == ':')
4380Sstevel@tonic-gate 			    current++;
4390Sstevel@tonic-gate 		    }
4400Sstevel@tonic-gate 
4410Sstevel@tonic-gate 		} else {
4420Sstevel@tonic-gate 
4430Sstevel@tonic-gate 		    /* Invalid severity definition, eat thru end of token */
4440Sstevel@tonic-gate 		    current = tokend;
4450Sstevel@tonic-gate 		    if (*tokend == ':')
4460Sstevel@tonic-gate 			current++;
4470Sstevel@tonic-gate 		}
4480Sstevel@tonic-gate 
4490Sstevel@tonic-gate 	    } else {
4500Sstevel@tonic-gate 
4510Sstevel@tonic-gate 		/* End of string found */
4520Sstevel@tonic-gate 		done = TRUE;
4530Sstevel@tonic-gate 		leftoff = (char *) NULL;
4540Sstevel@tonic-gate 	    }
4550Sstevel@tonic-gate 
4560Sstevel@tonic-gate 	} /* while (!done) */
4570Sstevel@tonic-gate 
4580Sstevel@tonic-gate 	/* Finished */
4590Sstevel@tonic-gate 	return(rtnval);
4600Sstevel@tonic-gate }
4610Sstevel@tonic-gate 
4620Sstevel@tonic-gate /*
4630Sstevel@tonic-gate  * fmtmsg [-a action] [-c classification] [-l label] [-s severity] [-t tag]
4640Sstevel@tonic-gate  *        [-u subclass[,subclass[,...]]] [text]
4650Sstevel@tonic-gate  *
4660Sstevel@tonic-gate  * Function:
4670Sstevel@tonic-gate  *	Writes a message in the standard format.  Typically used by shell
4680Sstevel@tonic-gate  *	scripts to write error messages to the user.
4690Sstevel@tonic-gate  *
4700Sstevel@tonic-gate  * Arguments:
4710Sstevel@tonic-gate  *	text		String that is the text of the message
4720Sstevel@tonic-gate  *
4730Sstevel@tonic-gate  * Options:
4740Sstevel@tonic-gate  *   -a action		String that describes user action to take to
4750Sstevel@tonic-gate  *			correct the situation
4760Sstevel@tonic-gate  *   -c classification	Keyword that identifies the type of the message
4770Sstevel@tonic-gate  *   -l label		String that identifies the source of the message
4780Sstevel@tonic-gate  *   -s severity	Keyword that identifies the severity of the message
4790Sstevel@tonic-gate  *   -t tag		String that identifies the message (use unclear)
4800Sstevel@tonic-gate  *   -u sub_classes	Comma-list of keywords that refines the type of
4810Sstevel@tonic-gate  *			the message
4820Sstevel@tonic-gate  *
4830Sstevel@tonic-gate  * Environment Variables Used:
4840Sstevel@tonic-gate  *	MSGVERB		Defines the pieces of a message the user expects
4850Sstevel@tonic-gate  *			to see.  It is a list of keywords separated by
4860Sstevel@tonic-gate  *			colons (':').
4870Sstevel@tonic-gate  *	SEV_LEVEL	Defines a list of auxiliary severity keywords, values,
4880Sstevel@tonic-gate  *			and print-strings.  It is a list of fields separated
4890Sstevel@tonic-gate  *			by colons (':').  Each field consists of three
4900Sstevel@tonic-gate  *			elements, keyword, value (in octal, hex, or decimal),
4910Sstevel@tonic-gate  *			and print-string, separated by commas (',').
4920Sstevel@tonic-gate  *
4930Sstevel@tonic-gate  * Needs:
4940Sstevel@tonic-gate  *
4950Sstevel@tonic-gate  * Open Issues:
4960Sstevel@tonic-gate  */
4970Sstevel@tonic-gate 
498*335Smuffin int
main(int argc,char ** argv)499*335Smuffin main(int argc, char **argv)
5000Sstevel@tonic-gate {
5010Sstevel@tonic-gate 
5020Sstevel@tonic-gate 	/* Local automatic data */
5030Sstevel@tonic-gate 
5040Sstevel@tonic-gate 	long			class;		/* Classification (built) */
5050Sstevel@tonic-gate 
5060Sstevel@tonic-gate 	int			severity;	/* User specified severity */
5070Sstevel@tonic-gate 	int			msgrtn;		/* Value returned by fmtmsg() */
5080Sstevel@tonic-gate 	int			optchar;	/* Opt char on cmdline */
5090Sstevel@tonic-gate 	int			exitval;	/* Value to return */
5100Sstevel@tonic-gate 
5110Sstevel@tonic-gate 	int			found;		/* FLAG, kywd found yet? */
5120Sstevel@tonic-gate 	int			errflg;		/* FLAG, error seen in cmd */
5130Sstevel@tonic-gate 	int			a_seen;		/* FLAG, -a option seen */
5140Sstevel@tonic-gate 	int			c_seen;		/* FLAG, -c option seen */
5150Sstevel@tonic-gate 	int			l_seen;		/* FLAG, -l option seen */
5160Sstevel@tonic-gate 	int			s_seen;		/* FLAG, -s option seen */
5170Sstevel@tonic-gate 	int			t_seen;		/* FLAG, -t option seen */
5180Sstevel@tonic-gate 	int			u_seen;		/* FLAG, -u option seen */
5190Sstevel@tonic-gate 	int			text_seen;	/* FLAG, text seen */
5200Sstevel@tonic-gate 
5210Sstevel@tonic-gate 	char		       *text;		/* Ptr to user's text */
5220Sstevel@tonic-gate 	char		       *label;		/* Ptr to user's label */
5230Sstevel@tonic-gate 	char		       *tag;		/* Ptr to user's tag */
5240Sstevel@tonic-gate 	char		       *action;		/* Ptr to user's action str */
5250Sstevel@tonic-gate 	char		       *sstr;		/* Ptr to -s (severity) arg */
5260Sstevel@tonic-gate 	char		       *ustr;		/* Ptr to -u (subclass) arg */
5270Sstevel@tonic-gate 	char		       *cstr;		/* Ptr to -c (class) arg */
5280Sstevel@tonic-gate 	char		       *sevstrval;	/* Ptr to SEV_LEVEL argument */
5290Sstevel@tonic-gate 	char		       *sevval;		/* Ptr to temp SEV_LEVEL arg */
5300Sstevel@tonic-gate 	char		       *tokenptr;	/* Ptr to current token */
5310Sstevel@tonic-gate 	char		       *cmdname;	/* Ptr to base command name */
5320Sstevel@tonic-gate 	char		       *p;		/* Multipurpose ptr */
5330Sstevel@tonic-gate 
5340Sstevel@tonic-gate 	struct class_info      *class_info;	/* Ptr to class/subclass info structure */
5350Sstevel@tonic-gate 	struct sev_info	       *sev_info;	/* Ptr to severity info struct */
5360Sstevel@tonic-gate 	struct sevstr	       *penvsev;	/* Ptr to SEV_LEVEL values */
5370Sstevel@tonic-gate 
5380Sstevel@tonic-gate 
5390Sstevel@tonic-gate 
5400Sstevel@tonic-gate 	/*
5410Sstevel@tonic-gate 	 * fmtmsg
5420Sstevel@tonic-gate 	 */
5430Sstevel@tonic-gate 
5440Sstevel@tonic-gate 
5450Sstevel@tonic-gate 	/* Initializations */
5460Sstevel@tonic-gate 
5470Sstevel@tonic-gate 
5480Sstevel@tonic-gate 	/* Extract the base command name from the command */
5490Sstevel@tonic-gate 	if ((p = strrchr(argv[0], '/')) == (char *) NULL)
5500Sstevel@tonic-gate 	    cmdname = argv[0];
5510Sstevel@tonic-gate 	else
5520Sstevel@tonic-gate 	    cmdname = p+1;
5530Sstevel@tonic-gate 
5540Sstevel@tonic-gate 	/* Build the label for messages from "fmtmsg" */
5550Sstevel@tonic-gate 	(void) snprintf(labelbuf, sizeof (labelbuf), "UX:%s", cmdname);
5560Sstevel@tonic-gate 
5570Sstevel@tonic-gate 
5580Sstevel@tonic-gate 	/*
5590Sstevel@tonic-gate 	 * Extract arguments from the command line
5600Sstevel@tonic-gate 	 */
5610Sstevel@tonic-gate 
5620Sstevel@tonic-gate 	/* Initializations */
5630Sstevel@tonic-gate 
5640Sstevel@tonic-gate 	opterr = 0;			/* Disable messages from getopt() */
5650Sstevel@tonic-gate 	errflg = FALSE;			/* No errors seen yet */
5660Sstevel@tonic-gate 
5670Sstevel@tonic-gate 	a_seen = FALSE;			/* No action (-a) text seen yet */
5680Sstevel@tonic-gate 	c_seen = FALSE;			/* No classification (-c) seen yet */
5690Sstevel@tonic-gate 	l_seen = FALSE;			/* No label (-l) seen yet */
5700Sstevel@tonic-gate 	s_seen = FALSE;			/* No severity (-s) seen yet */
5710Sstevel@tonic-gate 	t_seen = FALSE;			/* No tag (-t) seen yet */
5720Sstevel@tonic-gate 	u_seen = FALSE;			/* No subclass (-u) seen yet */
5730Sstevel@tonic-gate 	text_seen = FALSE;		/* No text seen yet */
5740Sstevel@tonic-gate 
5750Sstevel@tonic-gate 
5760Sstevel@tonic-gate 	/*
5770Sstevel@tonic-gate 	 * If only the command name was used, write out a usage string to
5780Sstevel@tonic-gate 	 * the standard output file.
5790Sstevel@tonic-gate 	 */
5800Sstevel@tonic-gate 
5810Sstevel@tonic-gate 	if (argc == 1) {
5820Sstevel@tonic-gate 	    (void) fputs(BIGUSAGE, stderr);
5830Sstevel@tonic-gate 	    exit(0);
5840Sstevel@tonic-gate 	}
5850Sstevel@tonic-gate 
5860Sstevel@tonic-gate 
5870Sstevel@tonic-gate 	/* Parce command line */
5880Sstevel@tonic-gate 	while (((optchar = getopt(argc, argv, "a:c:l:s:t:u:")) != EOF) &&
5890Sstevel@tonic-gate 	       !errflg) {
5900Sstevel@tonic-gate 
5910Sstevel@tonic-gate 	    switch(optchar) {
5920Sstevel@tonic-gate 
5930Sstevel@tonic-gate 	    case 'a':		/* -a actiontext */
5940Sstevel@tonic-gate 		if (!a_seen) {
5950Sstevel@tonic-gate 		    action = optarg;
5960Sstevel@tonic-gate 		    a_seen = TRUE;
5970Sstevel@tonic-gate 		} else errflg = TRUE;
5980Sstevel@tonic-gate 		break;
5990Sstevel@tonic-gate 
6000Sstevel@tonic-gate 	    case 'c':		/* -c classification */
6010Sstevel@tonic-gate 		if (!c_seen) {
6020Sstevel@tonic-gate 		    cstr = optarg;
6030Sstevel@tonic-gate 		    c_seen = TRUE;
6040Sstevel@tonic-gate 		} else errflg = TRUE;
6050Sstevel@tonic-gate 		break;
6060Sstevel@tonic-gate 
6070Sstevel@tonic-gate 	    case 'l':		/* -l label */
6080Sstevel@tonic-gate 		if (!l_seen) {
6090Sstevel@tonic-gate 		    label = optarg;
6100Sstevel@tonic-gate 		    l_seen = TRUE;
6110Sstevel@tonic-gate 		} else errflg = TRUE;
6120Sstevel@tonic-gate 		break;
6130Sstevel@tonic-gate 
6140Sstevel@tonic-gate 	    case 's':		/* -s severity */
6150Sstevel@tonic-gate 		if (!s_seen) {
6160Sstevel@tonic-gate 		    sstr = optarg;
6170Sstevel@tonic-gate 		    s_seen = TRUE;
6180Sstevel@tonic-gate 		} else errflg = TRUE;
6190Sstevel@tonic-gate 		break;
6200Sstevel@tonic-gate 
6210Sstevel@tonic-gate 	    case 't':		/* -t tag */
6220Sstevel@tonic-gate 		if (!t_seen) {
6230Sstevel@tonic-gate 		    tag = optarg;
6240Sstevel@tonic-gate 		    t_seen = TRUE;
6250Sstevel@tonic-gate 		} else errflg = TRUE;
6260Sstevel@tonic-gate 		break;
6270Sstevel@tonic-gate 
6280Sstevel@tonic-gate 	    case 'u':		/* -u subclasslist */
6290Sstevel@tonic-gate 		if (!u_seen) {
6300Sstevel@tonic-gate 		    ustr = optarg;
6310Sstevel@tonic-gate 		    u_seen = TRUE;
6320Sstevel@tonic-gate 		} else errflg = TRUE;
6330Sstevel@tonic-gate 		break;
6340Sstevel@tonic-gate 
6350Sstevel@tonic-gate 	    case '?':		/* -? or unknown option */
6360Sstevel@tonic-gate 	    default:
6370Sstevel@tonic-gate 		errflg = TRUE;
6380Sstevel@tonic-gate 		break;
6390Sstevel@tonic-gate 
6400Sstevel@tonic-gate 	    } /* esac */
6410Sstevel@tonic-gate 	}
6420Sstevel@tonic-gate 
6430Sstevel@tonic-gate 
6440Sstevel@tonic-gate 	/* Get the text */
6450Sstevel@tonic-gate 	if (!errflg) {
6460Sstevel@tonic-gate 	    if (argc == (optind+1)) {
6470Sstevel@tonic-gate 		text = argv[optind];
6480Sstevel@tonic-gate 		text_seen = TRUE;
6490Sstevel@tonic-gate 	    }
6500Sstevel@tonic-gate 	    else if (argc != optind) {
6510Sstevel@tonic-gate 		errflg = TRUE;
6520Sstevel@tonic-gate 	    }
6530Sstevel@tonic-gate 	}
6540Sstevel@tonic-gate 
6550Sstevel@tonic-gate 
6560Sstevel@tonic-gate 	/* Report syntax errors */
6570Sstevel@tonic-gate 	if (errflg) {
6580Sstevel@tonic-gate 	    (void) fputs(BIGUSAGE, stderr);
6590Sstevel@tonic-gate 	    exit(1);
6600Sstevel@tonic-gate 	}
6610Sstevel@tonic-gate 
6620Sstevel@tonic-gate 
6630Sstevel@tonic-gate 	/*
6640Sstevel@tonic-gate 	 * Classification.
6650Sstevel@tonic-gate 	 */
6660Sstevel@tonic-gate 
6670Sstevel@tonic-gate 	class = 0L;
6680Sstevel@tonic-gate 	if (c_seen) {
6690Sstevel@tonic-gate 
6700Sstevel@tonic-gate 	    /* Search for keyword in list */
6710Sstevel@tonic-gate 	    for (class_info = &classes[0] ;
6720Sstevel@tonic-gate 		 (class_info->keyword != (char *) NULL) &&
6730Sstevel@tonic-gate 		 (strcmp(cstr, class_info->keyword)) ;
6740Sstevel@tonic-gate 		 class_info++) ;
6750Sstevel@tonic-gate 
6760Sstevel@tonic-gate 	    /* If invalid (keyword unknown), write a message and exit */
6770Sstevel@tonic-gate 	    if (class_info->keyword == (char *) NULL) {
6780Sstevel@tonic-gate 		(void) snprintf(msgbuf, sizeof (msgbuf),
6790Sstevel@tonic-gate 			"Invalid class: %s", cstr);
6800Sstevel@tonic-gate 		(void) fmtmsg(CLASS, labelbuf, MM_ERROR, msgbuf,
6810Sstevel@tonic-gate 		              MM_NULLACT, MM_NULLTAG);
6820Sstevel@tonic-gate 		exit(1);
6830Sstevel@tonic-gate 	    }
6840Sstevel@tonic-gate 
6850Sstevel@tonic-gate 	    /* Save classification */
6860Sstevel@tonic-gate 	    class = class_info->value;
6870Sstevel@tonic-gate 
6880Sstevel@tonic-gate 	}
6890Sstevel@tonic-gate 
6900Sstevel@tonic-gate 
6910Sstevel@tonic-gate 	/*
6920Sstevel@tonic-gate 	 * Subclassification.
6930Sstevel@tonic-gate 	 */
6940Sstevel@tonic-gate 
6950Sstevel@tonic-gate 	if (u_seen) {
6960Sstevel@tonic-gate 
6970Sstevel@tonic-gate 	    errflg = FALSE;
6980Sstevel@tonic-gate 	    p = strcpy(malloc((unsigned int) strlen(ustr)+1), ustr);
6990Sstevel@tonic-gate 	    if ((tokenptr = strtok(p, ",")) == (char *) NULL) errflg = TRUE;
7000Sstevel@tonic-gate 	    else do {
7010Sstevel@tonic-gate 
7020Sstevel@tonic-gate 		/* Got a keyword.  Look for it in keyword list */
7030Sstevel@tonic-gate 		for (class_info = subclasses ;
7040Sstevel@tonic-gate 		     (class_info->keyword != (char *) NULL) &&
7050Sstevel@tonic-gate 		     (strcmp(tokenptr, class_info->keyword) != 0) ;
7060Sstevel@tonic-gate 		     class_info++) ;
7070Sstevel@tonic-gate 
7080Sstevel@tonic-gate 		/* If found in list and no conflict, remember in class */
7090Sstevel@tonic-gate 		if ((class_info->keyword != (char *) NULL) && ((class & class_info->conflict) == 0L))
7100Sstevel@tonic-gate 		    class |= class_info->value;
7110Sstevel@tonic-gate 		else
7120Sstevel@tonic-gate 		    errflg = TRUE;
7130Sstevel@tonic-gate 
7140Sstevel@tonic-gate 	    } while (!errflg && ((tokenptr = strtok((char *) NULL, ",")) != (char *) NULL)) ;
7150Sstevel@tonic-gate 
7160Sstevel@tonic-gate 	    if (errflg) {
7170Sstevel@tonic-gate 		(void) snprintf(msgbuf, sizeof (msgbuf),
7180Sstevel@tonic-gate 			"Invalid subclass: %s", ustr);
7190Sstevel@tonic-gate 		(void) fmtmsg(CLASS, labelbuf, MM_ERROR, msgbuf,
7200Sstevel@tonic-gate 		              MM_NULLACT, MM_NULLTAG);
7210Sstevel@tonic-gate 		exit(1);
7220Sstevel@tonic-gate 	    }
7230Sstevel@tonic-gate 
7240Sstevel@tonic-gate 	}
7250Sstevel@tonic-gate 
7260Sstevel@tonic-gate 	if (!c_seen & !u_seen) class = MM_NULLMC;
7270Sstevel@tonic-gate 
7280Sstevel@tonic-gate 
7290Sstevel@tonic-gate 
7300Sstevel@tonic-gate 	/*
7310Sstevel@tonic-gate 	 * Severity.
7320Sstevel@tonic-gate 	 */
7330Sstevel@tonic-gate 
7340Sstevel@tonic-gate 	if (s_seen) {
7350Sstevel@tonic-gate 
7360Sstevel@tonic-gate 	    /* If the severity is specified as a number, use that value */
7370Sstevel@tonic-gate 	    severity = strtol(sstr, &p, 10);
7380Sstevel@tonic-gate 	    if (*p || (strlen(sstr) == 0)) {
7390Sstevel@tonic-gate 
7400Sstevel@tonic-gate 		/* Look for the standard severities */
7410Sstevel@tonic-gate 		for (sev_info = severities ;
7420Sstevel@tonic-gate 		     (sev_info->keyword != (char *) NULL) &&
7430Sstevel@tonic-gate 		     (strcmp(sstr, sev_info->keyword)) ;
7440Sstevel@tonic-gate 		     sev_info++) ;
7450Sstevel@tonic-gate 
7460Sstevel@tonic-gate 		/*
7470Sstevel@tonic-gate 		 * If the "severity" argument is one of the standard keywords,
7480Sstevel@tonic-gate 		 * remember it for fmtmsg().  Otherwise, look at the SEV_LEVEL
7490Sstevel@tonic-gate 		 * environment variable for severity extensions.
7500Sstevel@tonic-gate 		 */
7510Sstevel@tonic-gate 
7520Sstevel@tonic-gate 		/* If the keyword is one of the standard ones, save severity */
7530Sstevel@tonic-gate 		if (sev_info->keyword != (char *) NULL) severity = sev_info->value;
7540Sstevel@tonic-gate 
7550Sstevel@tonic-gate 		else {
7560Sstevel@tonic-gate 
7570Sstevel@tonic-gate 		    /*
7580Sstevel@tonic-gate 		     * Severity keyword may be one of the extended set, if any.
7590Sstevel@tonic-gate 		     */
7600Sstevel@tonic-gate 
7610Sstevel@tonic-gate 		    /* Get the value of the SEV_LEVEL environment variable */
7620Sstevel@tonic-gate 		    found = FALSE;
7630Sstevel@tonic-gate 		    if ((sevstrval = getenv(SEV_LEVEL)) != (char *) NULL) {
7640Sstevel@tonic-gate 			sevval = (char *) malloc((unsigned int) strlen(sevstrval)+1);
7650Sstevel@tonic-gate 			penvsev = getauxsevs(strcpy(sevval, sevstrval));
7660Sstevel@tonic-gate 			if (penvsev != (struct sevstr *) NULL) do {
7670Sstevel@tonic-gate 			    if (strcmp(penvsev->sevkywd, sstr) == 0) {
7680Sstevel@tonic-gate 				severity = penvsev->sevvalue;
7690Sstevel@tonic-gate 				found = TRUE;
7700Sstevel@tonic-gate 			    }
7710Sstevel@tonic-gate 			    else {
7720Sstevel@tonic-gate 				free(penvsev);
7730Sstevel@tonic-gate 				penvsev = getauxsevs((char *) NULL);
7740Sstevel@tonic-gate 			    }
7750Sstevel@tonic-gate 			} while (!found && (penvsev != (struct sevstr *) NULL));
7760Sstevel@tonic-gate 
7770Sstevel@tonic-gate 			if (found) free(penvsev);
7780Sstevel@tonic-gate 			free(sevval);
7790Sstevel@tonic-gate 		    }
7800Sstevel@tonic-gate 
7810Sstevel@tonic-gate 		    if (!found) {
7820Sstevel@tonic-gate 			(void) snprintf(msgbuf, sizeof (msgbuf),
7830Sstevel@tonic-gate 				"Invalid severity: %s", sstr);
7840Sstevel@tonic-gate 			(void) fmtmsg(CLASS, labelbuf, MM_ERROR, msgbuf,
7850Sstevel@tonic-gate 				      MM_NULLACT, MM_NULLTAG);
7860Sstevel@tonic-gate 			exit(1);
7870Sstevel@tonic-gate 		    }
7880Sstevel@tonic-gate 
7890Sstevel@tonic-gate 		}  /* <severity> is not one of the standard severities */
7900Sstevel@tonic-gate 
7910Sstevel@tonic-gate 	    }  /* <severity> is not numeric */
7920Sstevel@tonic-gate 
7930Sstevel@tonic-gate 	}  /* if (s_seen) */
7940Sstevel@tonic-gate 
7950Sstevel@tonic-gate 	else severity = MM_NULLSEV;
7960Sstevel@tonic-gate 
7970Sstevel@tonic-gate 
7980Sstevel@tonic-gate 	/*
7990Sstevel@tonic-gate 	 * Other options
8000Sstevel@tonic-gate 	 */
8010Sstevel@tonic-gate 
8020Sstevel@tonic-gate 	if (!a_seen) action = MM_NULLACT;
8030Sstevel@tonic-gate 	if (!l_seen) label = MM_NULLLBL;
8040Sstevel@tonic-gate 	if (!t_seen) tag = MM_NULLTAG;
8050Sstevel@tonic-gate 	if (!text_seen) text = MM_NULLTXT;
8060Sstevel@tonic-gate 
8070Sstevel@tonic-gate 
8080Sstevel@tonic-gate 	/*
8090Sstevel@tonic-gate 	 * Write the message
8100Sstevel@tonic-gate 	 */
8110Sstevel@tonic-gate 
8120Sstevel@tonic-gate 	msgrtn = fmtmsg(class, label, severity, text, action ,tag);
8130Sstevel@tonic-gate 
8140Sstevel@tonic-gate 
8150Sstevel@tonic-gate 	/*
8160Sstevel@tonic-gate 	 * Return appropriate value to the shell (or wherever)
8170Sstevel@tonic-gate 	 */
8180Sstevel@tonic-gate 
8190Sstevel@tonic-gate 	exitval = 0;
8200Sstevel@tonic-gate 	if (msgrtn == MM_NOTOK) exitval = 32;
8210Sstevel@tonic-gate 	else {
8220Sstevel@tonic-gate 	    if (msgrtn & MM_NOMSG) exitval += 2;
8230Sstevel@tonic-gate 	    if (msgrtn & MM_NOCON) exitval += 4;
8240Sstevel@tonic-gate 	}
8250Sstevel@tonic-gate 
8260Sstevel@tonic-gate 	return(exitval);
8270Sstevel@tonic-gate }
828