1101353Smike/*- 2101353Smike * Copyright (c) 2002 Mike Barcroft <mike@FreeBSD.org> 3101353Smike * All rights reserved. 4101353Smike * 5101353Smike * Redistribution and use in source and binary forms, with or without 6101353Smike * modification, are permitted provided that the following conditions 7101353Smike * are met: 8101353Smike * 1. Redistributions of source code must retain the above copyright 9101353Smike * notice, this list of conditions and the following disclaimer. 10101353Smike * 2. Redistributions in binary form must reproduce the above copyright 11101353Smike * notice, this list of conditions and the following disclaimer in the 12101353Smike * documentation and/or other materials provided with the distribution. 13101353Smike * 14101353Smike * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15101353Smike * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16101353Smike * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17101353Smike * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18101353Smike * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19101353Smike * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20101353Smike * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21101353Smike * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22101353Smike * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23101353Smike * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24101353Smike * SUCH DAMAGE. 25101353Smike */ 26101353Smike 27101353Smike#include <sys/cdefs.h> 28101353Smike__FBSDID("$FreeBSD$"); 29101353Smike 30101353Smike#include <fmtmsg.h> 31101353Smike#include <stdio.h> 32101353Smike#include <stdlib.h> 33101353Smike#include <string.h> 34101353Smike 35101353Smike/* Default value for MSGVERB. */ 36101353Smike#define DFLT_MSGVERB "label:severity:text:action:tag" 37101353Smike 38101353Smike/* Maximum valid size for a MSGVERB. */ 39101353Smike#define MAX_MSGVERB sizeof(DFLT_MSGVERB) 40101353Smike 41101353Smikestatic char *printfmt(char *, long, const char *, int, const char *, 42101353Smike const char *, const char *); 43101353Smikestatic char *nextcomp(const char *); 44101353Smikestatic const char 45101353Smike *sevinfo(int); 46101353Smikestatic int validmsgverb(const char *); 47101353Smike 48101353Smikestatic const char *validlist[] = { 49101353Smike "label", "severity", "text", "action", "tag", NULL 50101353Smike}; 51101353Smike 52101353Smikeint 53101353Smikefmtmsg(long class, const char *label, int sev, const char *text, 54101353Smike const char *action, const char *tag) 55101353Smike{ 56101353Smike FILE *fp; 57101353Smike char *env, *msgverb, *output; 58101353Smike 59101353Smike if (class & MM_PRINT) { 60101353Smike if ((env = getenv("MSGVERB")) != NULL && *env != '\0' && 61101353Smike strlen(env) <= strlen(DFLT_MSGVERB)) { 62101353Smike if ((msgverb = strdup(env)) == NULL) 63101353Smike return (MM_NOTOK); 64101403Smike else if (validmsgverb(msgverb) == 0) { 65101403Smike free(msgverb); 66101353Smike goto def; 67101403Smike } 68101353Smike } else { 69101353Smikedef: 70101353Smike if ((msgverb = strdup(DFLT_MSGVERB)) == NULL) 71101353Smike return (MM_NOTOK); 72101353Smike } 73101353Smike output = printfmt(msgverb, class, label, sev, text, action, 74101353Smike tag); 75102750Smike if (output == NULL) { 76102750Smike free(msgverb); 77101353Smike return (MM_NOTOK); 78102750Smike } 79101353Smike if (*output != '\0') 80101353Smike fprintf(stderr, "%s", output); 81101353Smike free(msgverb); 82101353Smike free(output); 83101353Smike } 84101353Smike if (class & MM_CONSOLE) { 85101353Smike output = printfmt(DFLT_MSGVERB, class, label, sev, text, 86101353Smike action, tag); 87101353Smike if (output == NULL) 88101353Smike return (MM_NOCON); 89101353Smike if (*output != '\0') { 90101353Smike if ((fp = fopen("/dev/console", "a")) == NULL) { 91101353Smike free(output); 92101353Smike return (MM_NOCON); 93101353Smike } 94101353Smike fprintf(fp, "%s", output); 95101353Smike fclose(fp); 96101353Smike } 97101353Smike free(output); 98101353Smike } 99101353Smike return (MM_OK); 100101353Smike} 101101353Smike 102101353Smike#define INSERT_COLON \ 103101353Smike if (*output != '\0') \ 104114443Snectar strlcat(output, ": ", size) 105101353Smike#define INSERT_NEWLINE \ 106101353Smike if (*output != '\0') \ 107114443Snectar strlcat(output, "\n", size) 108101353Smike#define INSERT_SPACE \ 109101353Smike if (*output != '\0') \ 110114443Snectar strlcat(output, " ", size) 111101353Smike 112101353Smike/* 113101353Smike * Returns NULL on memory allocation failure, otherwise returns a pointer to 114101353Smike * a newly malloc()'d output buffer. 115101353Smike */ 116101353Smikestatic char * 117101353Smikeprintfmt(char *msgverb, long class, const char *label, int sev, 118101353Smike const char *text, const char *act, const char *tag) 119101353Smike{ 120101353Smike size_t size; 121101353Smike char *comp, *output; 122101353Smike const char *sevname; 123101353Smike 124101353Smike size = 32; 125101353Smike if (label != MM_NULLLBL) 126101353Smike size += strlen(label); 127101353Smike if ((sevname = sevinfo(sev)) != NULL) 128101353Smike size += strlen(sevname); 129101353Smike if (text != MM_NULLTXT) 130101353Smike size += strlen(text); 131199046Sbrueffer if (act != MM_NULLACT) 132101353Smike size += strlen(act); 133101353Smike if (tag != MM_NULLTAG) 134101353Smike size += strlen(tag); 135101353Smike 136101353Smike if ((output = malloc(size)) == NULL) 137101353Smike return (NULL); 138101353Smike *output = '\0'; 139101353Smike while ((comp = nextcomp(msgverb)) != NULL) { 140101353Smike if (strcmp(comp, "label") == 0 && label != MM_NULLLBL) { 141101353Smike INSERT_COLON; 142114443Snectar strlcat(output, label, size); 143101353Smike } else if (strcmp(comp, "severity") == 0 && sevname != NULL) { 144101353Smike INSERT_COLON; 145114443Snectar strlcat(output, sevinfo(sev), size); 146101353Smike } else if (strcmp(comp, "text") == 0 && text != MM_NULLTXT) { 147101353Smike INSERT_COLON; 148114443Snectar strlcat(output, text, size); 149101353Smike } else if (strcmp(comp, "action") == 0 && act != MM_NULLACT) { 150101353Smike INSERT_NEWLINE; 151114443Snectar strlcat(output, "TO FIX: ", size); 152114443Snectar strlcat(output, act, size); 153101353Smike } else if (strcmp(comp, "tag") == 0 && tag != MM_NULLTAG) { 154101353Smike INSERT_SPACE; 155114443Snectar strlcat(output, tag, size); 156101353Smike } 157101353Smike } 158101353Smike INSERT_NEWLINE; 159101353Smike return (output); 160101353Smike} 161101353Smike 162101403Smike/* 163101403Smike * Returns a component of a colon delimited string. NULL is returned to 164101403Smike * indicate that there are no remaining components. This function must be 165101403Smike * called until it returns NULL in order for the local state to be cleared. 166101403Smike */ 167101353Smikestatic char * 168101353Smikenextcomp(const char *msgverb) 169101353Smike{ 170101353Smike static char lmsgverb[MAX_MSGVERB], *state; 171101353Smike char *retval; 172101353Smike 173101353Smike if (*lmsgverb == '\0') { 174114443Snectar strlcpy(lmsgverb, msgverb, sizeof(lmsgverb)); 175101353Smike retval = strtok_r(lmsgverb, ":", &state); 176101353Smike } else { 177101353Smike retval = strtok_r(NULL, ":", &state); 178101353Smike } 179101353Smike if (retval == NULL) 180101353Smike *lmsgverb = '\0'; 181101353Smike return (retval); 182101353Smike} 183101353Smike 184101353Smikestatic const char * 185101353Smikesevinfo(int sev) 186101353Smike{ 187101353Smike 188101353Smike switch (sev) { 189101353Smike case MM_HALT: 190101353Smike return ("HALT"); 191101353Smike case MM_ERROR: 192101353Smike return ("ERROR"); 193101353Smike case MM_WARNING: 194101353Smike return ("WARNING"); 195101353Smike case MM_INFO: 196101353Smike return ("INFO"); 197101353Smike default: 198101353Smike return (NULL); 199101353Smike } 200101353Smike} 201101353Smike 202101353Smike/* 203101353Smike * Returns 1 if the msgverb list is valid, otherwise 0. 204101353Smike */ 205101353Smikestatic int 206101353Smikevalidmsgverb(const char *msgverb) 207101353Smike{ 208101353Smike char *msgcomp; 209101403Smike int i, equality; 210101353Smike 211101403Smike equality = 0; 212101353Smike while ((msgcomp = nextcomp(msgverb)) != NULL) { 213101403Smike equality--; 214101403Smike for (i = 0; validlist[i] != NULL; i++) { 215101403Smike if (strcmp(msgcomp, validlist[i]) == 0) 216101403Smike equality++; 217101353Smike } 218101353Smike } 219101403Smike return (!equality); 220101353Smike} 221