diff options
| author | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
|---|---|---|
| committer | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
| commit | 7c478bd95313f5f23a4c958a745db2134aa03244 (patch) | |
| tree | c871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/cmd/fmtmsg | |
| download | illumos-joyent-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz | |
OpenSolaris Launch
Diffstat (limited to 'usr/src/cmd/fmtmsg')
| -rw-r--r-- | usr/src/cmd/fmtmsg/Makefile | 50 | ||||
| -rw-r--r-- | usr/src/cmd/fmtmsg/main.c | 829 |
2 files changed, 879 insertions, 0 deletions
diff --git a/usr/src/cmd/fmtmsg/Makefile b/usr/src/cmd/fmtmsg/Makefile new file mode 100644 index 0000000000..7c8b77a890 --- /dev/null +++ b/usr/src/cmd/fmtmsg/Makefile @@ -0,0 +1,50 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +#ident "%Z%%M% %I% %E% SMI" +# +# Copyright (c) 1989 by Sun Microsystems, Inc. +# + +PROG= fmtmsg +OBJS= main.o +SRCS= $(OBJS:%.o=%.c) + +include ../Makefile.cmd + +.KEEP_STATE: + +all: $(PROG) + +$(PROG): $(OBJS) + $(LINK.c) $(OBJS) -o $@ $(LDLIBS) + $(POST_PROCESS) + +install: all $(ROOTPROG) + +clean: + $(RM) $(OBJS) + +lint: + $(LINT.c) $(SRCS) + +include ../Makefile.targ diff --git a/usr/src/cmd/fmtmsg/main.c b/usr/src/cmd/fmtmsg/main.c new file mode 100644 index 0000000000..9a35f55d76 --- /dev/null +++ b/usr/src/cmd/fmtmsg/main.c @@ -0,0 +1,829 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + + +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + + +/* + * fmtmsg.c + * + * Contains: + * fmtmsg Command that writes a message in the standard + * message format. May in future make these + * messages available for logging. + */ + + +/* + * Header files used: + * <stdio.h> C Standard I/O function definitions + * <string.h> C string-handling definitions + * <errno.h> UNIX error-code "errno" definitions + * <fmtmsg.h> Standard Message definitions + */ + +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <fmtmsg.h> + + +/* + * Externals referenced: + * strtol Function that converts char strings to "long" + * fmtmsg Function that writes a message in standard format + * getenv Function that extracts an environment variable's + * value + * malloc Allocate memory from the memory pool + * free Frees allocated memory + * getopt Function that extracts arguments from the command- + * optarg Points to option's argument (from getopt()) + * optind Option's argument index (from getopt()) + * opterr FLAG, write error if invalid option (for getopt()) + * line. + * exit Exits the command + */ + +extern long strtol(); +extern int fmtmsg(); +extern char *getenv(); +extern void *malloc(); +extern void free(); +extern int getopt(); +extern char *optarg; +extern int optind; +extern int opterr; +extern void exit(); + +/* + * Local definitions + */ + +/* + * Local constants + */ + + +/* + * Boolean constants + * TRUE Boolean value for "true" (any bits on) + * FALSE Boolean value for "false" (all bits off) + */ + +#ifndef FALSE +#define FALSE (0) +#endif + +#ifndef TRUE +#define TRUE (1) +#endif + + +#define CLASS (MM_PRINT|MM_SOFT|MM_NRECOV|MM_UTIL) +#define BIGUSAGE "fmtmsg [-a action] [-c class] [-l label] [-s severity] [-t tag]\n [-u subclass[,subclass[,...]]] [text]\n" + + +/* + * Local data-type definitions + */ + +/* + * Structure used for tables containing keywords and integer values + */ + +struct sev_info { + char *keyword; + int value; +}; + + +/* + * Structure used for tables containing keywords, long values + */ + +struct class_info { + char *keyword; + long value; + long conflict; +}; + + +/* + * Severity string structure + * + * struct sevstr + * sevvalue Value of the severity-level being defined + * sevkywd Keyword identifying the severity + * sevprptr Pointer to the string associated with the value + * sevnext Pointer to the next value in the list. + */ + +struct sevstr { + int sevvalue; + char *sevkywd; + char *sevprstr; + struct sevstr *sevnext; +}; + + +/* + * Local static data + */ + + +/* + * Table contains the keywords for the classes of a message + */ + +static struct class_info classes[] = { + + {"hard", MM_HARD, MM_SOFT|MM_FIRM}, /* hardware */ + {"soft", MM_SOFT, MM_HARD|MM_FIRM}, /* software */ + {"firm", MM_FIRM, MM_SOFT|MM_FIRM}, /* firmware */ + + {(char *) NULL, 0L, 0L} /* end of list */ + +}; + + +/* + * Table contains the keywords for the subclasses for a message + */ + +static struct class_info subclasses[] = { + + {"appl", MM_APPL, MM_UTIL|MM_OPSYS}, /* Application */ + {"util", MM_UTIL, MM_APPL|MM_OPSYS}, /* Utility */ + {"opsys", MM_OPSYS, MM_APPL|MM_UTIL}, /* Operating System */ + + {"recov", MM_RECOVER, MM_NRECOV}, /* Recoverable */ + {"nrecov", MM_NRECOV, MM_RECOVER}, /* Non-recoverable */ + + {"print", MM_PRINT, 0L}, /* Write message to stderr */ + {"console", MM_CONSOLE, 0L}, /* Write message on /dev/console */ + {(char *) NULL, 0L, 0L} /* End of list */ + +}; + + +/* + * Table contains the keywords for the standard severities of a message. + * User may supply more through the SEV_LEVEL environment variable. + */ + +static struct sev_info severities[] = { + {"halt", MM_HALT}, /* halt */ + {"error", MM_ERROR}, /* error */ + {"warn", MM_WARNING}, /* warn */ + {"info", MM_INFO}, /* info */ + {(char *) NULL, 0} /* end of list */ +}; + + +/* + * Buffers used by the command + */ + +static char labelbuf[128]; /* Buf for message label */ +static char msgbuf[256]; /* Buf for messages */ + +/* + * static char *exttok(str, delims) + * char *str + * char *delims + * + * This function examines the string pointed to by "str", looking + * for the first occurrence of any of the characters in the string + * whose address is "delims". It returns the address of that + * character or (char *) NULL if there was nothing to search. + * + * Arguments: + * str Address of the string to search + * delims Address of the string containing delimiters + * + * Returns: char * + * Returns the address of the first occurrence of any of the characters + * in "delim" in the string "str" (incl '\0'). If there was nothing + * to search, the function returns (char *) NULL. + * + * Notes: + * - This function is needed because strtok() can't be used inside a + * function. Besides, strtok() is destructive in the string, which + * is undesirable in many circumstances. + * - This function understands escaped delimiters as non-delimiters. + * Delimiters are escaped by preceding them with '\' characters. + * The '\' character also must be escaped. + */ + +static char * +exttok(tok, delims) + char *tok; /* Ptr to the token we're parsing */ + char *delims; /* Ptr to string with delimiters */ +{ + + /* Automatic Data */ + char *tokend; /* Ptr to the end of the token */ + char *p, *q; /* Temp pointers */ + + + /* Algorithm: + * 1. Get the starting address (new string or where we + * left off). If nothing to search, return (char *) NULL + * 2. Find the end of the string + * 3. Look for the first unescaped delimiter closest to the + * beginning of the string + * 4. Remember where we left off + * 5. Return a pointer to the delimiter we found + */ + + /* Begin at the beginning, if any */ + if (tok == (char *) NULL) { + return ((char *) NULL); + } + + /* Find end of the token string */ + tokend = tok + strlen(tok); + + /* Look for the 1st occurrence of any delimiter */ + for (p = delims ; *p != '\0' ; p++) { + for (q = strchr(tok, *p) ; q && (q != tok) && (*(q-1) == '\\') ; q = strchr(q+1, *p)) ; + if (q && (q < tokend)) tokend = q; + } + + /* Done */ + return(tokend); +} + +/* + * char *noesc(str) + * + * This function squeezes out all of the escaped character sequences + * from the string <str>. It returns a pointer to that string. + * + * Arguments: + * str char * + * The string that is to have its escaped characters removed. + * + * Returns: char * + * This function returns its argument <str> always. + * + * Notes: + * This function potentially modifies the string it is given. + */ + +char * +noesc(str) + char *str; /* String to remove escaped characters from */ +{ + char *p; /* Temp string pointer */ + char *q; /* Temp string pointer */ + + /* Look for an escaped character */ + p = str; + while (*p && (*p != '\\')) p++; + + + /* + * If there was at least one, squeeze them out + * Otherwise, don't touch the argument string + */ + + if (*p) { + q = p++; + while (*q++ = *p++) if (*p == '\\') p++; + } + + /* Finished. Return our argument */ + return(str); +} + +/* + * struct sevstr *getauxsevs(ptr) + * + * Parses a string that is in the format of the severity definitions. + * Returns a pointer to a (malloc'd) structure that contains the + * definition, or (struct sevstr *) NULL if none was parsed. + * + * Arguments: + * ptr char * + * References the string from which data is to be extracted. + * If (char *) NULL, continue where we left off. Otherwise, + * start with the string referenced by ptr. + * + * Returns: struct sevstr * + * A pointer to a malloc'd structure containing the severity definition + * parsed from string, or (struct sevstr *) NULL if none. + * + * Notes: + * - This function is destructive to the string referenced by its argument. + */ + + +/* Static data */ +static char *leftoff = (char *) NULL; + +static struct sevstr * +getauxsevs(ptr) + char *ptr; +{ + + /* Automatic data */ + char *current; /* Ptr to current sev def'n */ + char *tokend; /* Ptr to end of current sev def'n */ + char *kywd; /* Ptr to extracted kywd */ + char *valstr; /* Ptr to extracted sev value */ + char *prstr; /* Ptr to extracted print str */ + char *p; /* Temp pointer */ + int val; /* Converted severity value */ + int done; /* Flag, sev def'n found and ok? */ + struct sevstr *rtnval; /* Value to return */ + + + /* Start anew or start where we left off? */ + current = (ptr == (char *) NULL) ? leftoff : ptr; + + + /* If nothing to parse, return (char *) NULL */ + if (current == (char *) NULL) { + return ((struct sevstr *) NULL); + } + + + /* + * Look through the string "current" for a token of the form + * <kywd>,<sev>,<printstring> delimited by ':' or '\0' + */ + + /* Loop initializations */ + done = FALSE; + rtnval = (struct sevstr *) NULL; + while (!done) { + + /* Eat leading junk */ + while (*(tokend = exttok(current, ":,")) == ':') { + current = tokend + 1; + } + + /* If we've found a <kywd>,... */ + if (*tokend == ',') { + kywd = current; + *tokend = '\0'; + + /* Look for <kywd>,<sev>,... */ + current = tokend + 1; + if (*(tokend = exttok(current, ":,")) == ',') { + valstr = current; + *tokend = '\0'; + current = tokend+1; + prstr = current; + + /* Make sure <sev> > 4 */ + val = (int) strtol(noesc(valstr), &p, 0); + if ((val > 4) && (p == tokend)) { + + /* + * Found <kywd>,<sev>,<printstring>. + * remember where we left off + */ + + if (*(tokend = exttok(current, ":")) == ':') { + *tokend = '\0'; + leftoff = tokend + 1; + } else leftoff = (char *) NULL; + + /* Alloc structure to contain severity definition */ + if (rtnval = (struct sevstr *) malloc(sizeof(struct sevstr))) { + + /* Fill in structure */ + rtnval->sevkywd = noesc(kywd); + rtnval->sevvalue = val; + rtnval->sevprstr = noesc(prstr); + rtnval->sevnext = (struct sevstr *) NULL; + } + + done = TRUE; + + } else { + + /* Invalid severity value, eat thru end of token */ + current = tokend; + if (*(tokend = exttok(prstr, ":")) == ':') + current++; + } + + } else { + + /* Invalid severity definition, eat thru end of token */ + current = tokend; + if (*tokend == ':') + current++; + } + + } else { + + /* End of string found */ + done = TRUE; + leftoff = (char *) NULL; + } + + } /* while (!done) */ + + /* Finished */ + return(rtnval); +} + +/* + * fmtmsg [-a action] [-c classification] [-l label] [-s severity] [-t tag] + * [-u subclass[,subclass[,...]]] [text] + * + * Function: + * Writes a message in the standard format. Typically used by shell + * scripts to write error messages to the user. + * + * Arguments: + * text String that is the text of the message + * + * Options: + * -a action String that describes user action to take to + * correct the situation + * -c classification Keyword that identifies the type of the message + * -l label String that identifies the source of the message + * -s severity Keyword that identifies the severity of the message + * -t tag String that identifies the message (use unclear) + * -u sub_classes Comma-list of keywords that refines the type of + * the message + * + * Environment Variables Used: + * MSGVERB Defines the pieces of a message the user expects + * to see. It is a list of keywords separated by + * colons (':'). + * SEV_LEVEL Defines a list of auxiliary severity keywords, values, + * and print-strings. It is a list of fields separated + * by colons (':'). Each field consists of three + * elements, keyword, value (in octal, hex, or decimal), + * and print-string, separated by commas (','). + * + * Needs: + * + * Open Issues: + */ + +main(argc, argv) + int argc; /* Argument count */ + char *argv[]; /* Pointers to arguments */ +{ + + /* Local automatic data */ + + long class; /* Classification (built) */ + + int severity; /* User specified severity */ + int msgrtn; /* Value returned by fmtmsg() */ + int optchar; /* Opt char on cmdline */ + int exitval; /* Value to return */ + + int found; /* FLAG, kywd found yet? */ + int errflg; /* FLAG, error seen in cmd */ + int a_seen; /* FLAG, -a option seen */ + int c_seen; /* FLAG, -c option seen */ + int l_seen; /* FLAG, -l option seen */ + int s_seen; /* FLAG, -s option seen */ + int t_seen; /* FLAG, -t option seen */ + int u_seen; /* FLAG, -u option seen */ + int text_seen; /* FLAG, text seen */ + + char *text; /* Ptr to user's text */ + char *label; /* Ptr to user's label */ + char *tag; /* Ptr to user's tag */ + char *action; /* Ptr to user's action str */ + char *sstr; /* Ptr to -s (severity) arg */ + char *ustr; /* Ptr to -u (subclass) arg */ + char *cstr; /* Ptr to -c (class) arg */ + char *sevstrval; /* Ptr to SEV_LEVEL argument */ + char *sevval; /* Ptr to temp SEV_LEVEL arg */ + char *tokenptr; /* Ptr to current token */ + char *cmdname; /* Ptr to base command name */ + char *p; /* Multipurpose ptr */ + + struct class_info *class_info; /* Ptr to class/subclass info structure */ + struct sev_info *sev_info; /* Ptr to severity info struct */ + struct sevstr *penvsev; /* Ptr to SEV_LEVEL values */ + + + + /* + * fmtmsg + */ + + + /* Initializations */ + + + /* Extract the base command name from the command */ + if ((p = strrchr(argv[0], '/')) == (char *) NULL) + cmdname = argv[0]; + else + cmdname = p+1; + + /* Build the label for messages from "fmtmsg" */ + (void) snprintf(labelbuf, sizeof (labelbuf), "UX:%s", cmdname); + + + /* + * Extract arguments from the command line + */ + + /* Initializations */ + + opterr = 0; /* Disable messages from getopt() */ + errflg = FALSE; /* No errors seen yet */ + + a_seen = FALSE; /* No action (-a) text seen yet */ + c_seen = FALSE; /* No classification (-c) seen yet */ + l_seen = FALSE; /* No label (-l) seen yet */ + s_seen = FALSE; /* No severity (-s) seen yet */ + t_seen = FALSE; /* No tag (-t) seen yet */ + u_seen = FALSE; /* No subclass (-u) seen yet */ + text_seen = FALSE; /* No text seen yet */ + + + /* + * If only the command name was used, write out a usage string to + * the standard output file. + */ + + if (argc == 1) { + (void) fputs(BIGUSAGE, stderr); + exit(0); + } + + + /* Parce command line */ + while (((optchar = getopt(argc, argv, "a:c:l:s:t:u:")) != EOF) && + !errflg) { + + switch(optchar) { + + case 'a': /* -a actiontext */ + if (!a_seen) { + action = optarg; + a_seen = TRUE; + } else errflg = TRUE; + break; + + case 'c': /* -c classification */ + if (!c_seen) { + cstr = optarg; + c_seen = TRUE; + } else errflg = TRUE; + break; + + case 'l': /* -l label */ + if (!l_seen) { + label = optarg; + l_seen = TRUE; + } else errflg = TRUE; + break; + + case 's': /* -s severity */ + if (!s_seen) { + sstr = optarg; + s_seen = TRUE; + } else errflg = TRUE; + break; + + case 't': /* -t tag */ + if (!t_seen) { + tag = optarg; + t_seen = TRUE; + } else errflg = TRUE; + break; + + case 'u': /* -u subclasslist */ + if (!u_seen) { + ustr = optarg; + u_seen = TRUE; + } else errflg = TRUE; + break; + + case '?': /* -? or unknown option */ + default: + errflg = TRUE; + break; + + } /* esac */ + } + + + /* Get the text */ + if (!errflg) { + if (argc == (optind+1)) { + text = argv[optind]; + text_seen = TRUE; + } + else if (argc != optind) { + errflg = TRUE; + } + } + + + /* Report syntax errors */ + if (errflg) { + (void) fputs(BIGUSAGE, stderr); + exit(1); + } + + + /* + * Classification. + */ + + class = 0L; + if (c_seen) { + + /* Search for keyword in list */ + for (class_info = &classes[0] ; + (class_info->keyword != (char *) NULL) && + (strcmp(cstr, class_info->keyword)) ; + class_info++) ; + + /* If invalid (keyword unknown), write a message and exit */ + if (class_info->keyword == (char *) NULL) { + (void) snprintf(msgbuf, sizeof (msgbuf), + "Invalid class: %s", cstr); + (void) fmtmsg(CLASS, labelbuf, MM_ERROR, msgbuf, + MM_NULLACT, MM_NULLTAG); + exit(1); + } + + /* Save classification */ + class = class_info->value; + + } + + + /* + * Subclassification. + */ + + if (u_seen) { + + errflg = FALSE; + p = strcpy(malloc((unsigned int) strlen(ustr)+1), ustr); + if ((tokenptr = strtok(p, ",")) == (char *) NULL) errflg = TRUE; + else do { + + /* Got a keyword. Look for it in keyword list */ + for (class_info = subclasses ; + (class_info->keyword != (char *) NULL) && + (strcmp(tokenptr, class_info->keyword) != 0) ; + class_info++) ; + + /* If found in list and no conflict, remember in class */ + if ((class_info->keyword != (char *) NULL) && ((class & class_info->conflict) == 0L)) + class |= class_info->value; + else + errflg = TRUE; + + } while (!errflg && ((tokenptr = strtok((char *) NULL, ",")) != (char *) NULL)) ; + + if (errflg) { + (void) snprintf(msgbuf, sizeof (msgbuf), + "Invalid subclass: %s", ustr); + (void) fmtmsg(CLASS, labelbuf, MM_ERROR, msgbuf, + MM_NULLACT, MM_NULLTAG); + exit(1); + } + + } + + if (!c_seen & !u_seen) class = MM_NULLMC; + + + + /* + * Severity. + */ + + if (s_seen) { + + /* If the severity is specified as a number, use that value */ + severity = strtol(sstr, &p, 10); + if (*p || (strlen(sstr) == 0)) { + + /* Look for the standard severities */ + for (sev_info = severities ; + (sev_info->keyword != (char *) NULL) && + (strcmp(sstr, sev_info->keyword)) ; + sev_info++) ; + + /* + * If the "severity" argument is one of the standard keywords, + * remember it for fmtmsg(). Otherwise, look at the SEV_LEVEL + * environment variable for severity extensions. + */ + + /* If the keyword is one of the standard ones, save severity */ + if (sev_info->keyword != (char *) NULL) severity = sev_info->value; + + else { + + /* + * Severity keyword may be one of the extended set, if any. + */ + + /* Get the value of the SEV_LEVEL environment variable */ + found = FALSE; + if ((sevstrval = getenv(SEV_LEVEL)) != (char *) NULL) { + sevval = (char *) malloc((unsigned int) strlen(sevstrval)+1); + penvsev = getauxsevs(strcpy(sevval, sevstrval)); + if (penvsev != (struct sevstr *) NULL) do { + if (strcmp(penvsev->sevkywd, sstr) == 0) { + severity = penvsev->sevvalue; + found = TRUE; + } + else { + free(penvsev); + penvsev = getauxsevs((char *) NULL); + } + } while (!found && (penvsev != (struct sevstr *) NULL)); + + if (found) free(penvsev); + free(sevval); + } + + if (!found) { + (void) snprintf(msgbuf, sizeof (msgbuf), + "Invalid severity: %s", sstr); + (void) fmtmsg(CLASS, labelbuf, MM_ERROR, msgbuf, + MM_NULLACT, MM_NULLTAG); + exit(1); + } + + } /* <severity> is not one of the standard severities */ + + } /* <severity> is not numeric */ + + } /* if (s_seen) */ + + else severity = MM_NULLSEV; + + + /* + * Other options + */ + + if (!a_seen) action = MM_NULLACT; + if (!l_seen) label = MM_NULLLBL; + if (!t_seen) tag = MM_NULLTAG; + if (!text_seen) text = MM_NULLTXT; + + + /* + * Write the message + */ + + msgrtn = fmtmsg(class, label, severity, text, action ,tag); + + + /* + * Return appropriate value to the shell (or wherever) + */ + + exitval = 0; + if (msgrtn == MM_NOTOK) exitval = 32; + else { + if (msgrtn & MM_NOMSG) exitval += 2; + if (msgrtn & MM_NOCON) exitval += 4; + } + + exit(exitval); + return(exitval); +} |
