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