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 48101353Smikeint 49101353Smikefmtmsg(long class, const char *label, int sev, const char *text, 50101353Smike const char *action, const char *tag) 51101353Smike{ 52101353Smike FILE *fp; 53101353Smike char *env, *msgverb, *output; 54101353Smike 55101353Smike if (class & MM_PRINT) { 56101353Smike if ((env = getenv("MSGVERB")) != NULL && *env != '\0' && 57101353Smike strlen(env) <= strlen(DFLT_MSGVERB)) { 58101353Smike if ((msgverb = strdup(env)) == NULL) 59101353Smike return (MM_NOTOK); 60101403Smike else if (validmsgverb(msgverb) == 0) { 61101403Smike free(msgverb); 62101353Smike goto def; 63101403Smike } 64101353Smike } else { 65101353Smikedef: 66101353Smike if ((msgverb = strdup(DFLT_MSGVERB)) == NULL) 67101353Smike return (MM_NOTOK); 68101353Smike } 69101353Smike output = printfmt(msgverb, class, label, sev, text, action, 70101353Smike tag); 71102750Smike if (output == NULL) { 72102750Smike free(msgverb); 73101353Smike return (MM_NOTOK); 74102750Smike } 75101353Smike if (*output != '\0') 76101353Smike fprintf(stderr, "%s", output); 77101353Smike free(msgverb); 78101353Smike free(output); 79101353Smike } 80101353Smike if (class & MM_CONSOLE) { 81101353Smike output = printfmt(DFLT_MSGVERB, class, label, sev, text, 82101353Smike action, tag); 83101353Smike if (output == NULL) 84101353Smike return (MM_NOCON); 85101353Smike if (*output != '\0') { 86244092Sjilles if ((fp = fopen("/dev/console", "ae")) == NULL) { 87101353Smike free(output); 88101353Smike return (MM_NOCON); 89101353Smike } 90101353Smike fprintf(fp, "%s", output); 91101353Smike fclose(fp); 92101353Smike } 93101353Smike free(output); 94101353Smike } 95101353Smike return (MM_OK); 96101353Smike} 97101353Smike 98101353Smike#define INSERT_COLON \ 99101353Smike if (*output != '\0') \ 100114443Snectar strlcat(output, ": ", size) 101101353Smike#define INSERT_NEWLINE \ 102101353Smike if (*output != '\0') \ 103114443Snectar strlcat(output, "\n", size) 104101353Smike#define INSERT_SPACE \ 105101353Smike if (*output != '\0') \ 106114443Snectar strlcat(output, " ", size) 107101353Smike 108101353Smike/* 109101353Smike * Returns NULL on memory allocation failure, otherwise returns a pointer to 110101353Smike * a newly malloc()'d output buffer. 111101353Smike */ 112101353Smikestatic char * 113101353Smikeprintfmt(char *msgverb, long class, const char *label, int sev, 114101353Smike const char *text, const char *act, const char *tag) 115101353Smike{ 116101353Smike size_t size; 117101353Smike char *comp, *output; 118101353Smike const char *sevname; 119101353Smike 120101353Smike size = 32; 121101353Smike if (label != MM_NULLLBL) 122101353Smike size += strlen(label); 123101353Smike if ((sevname = sevinfo(sev)) != NULL) 124101353Smike size += strlen(sevname); 125101353Smike if (text != MM_NULLTXT) 126101353Smike size += strlen(text); 127199046Sbrueffer if (act != MM_NULLACT) 128101353Smike size += strlen(act); 129101353Smike if (tag != MM_NULLTAG) 130101353Smike size += strlen(tag); 131101353Smike 132101353Smike if ((output = malloc(size)) == NULL) 133101353Smike return (NULL); 134101353Smike *output = '\0'; 135101353Smike while ((comp = nextcomp(msgverb)) != NULL) { 136101353Smike if (strcmp(comp, "label") == 0 && label != MM_NULLLBL) { 137101353Smike INSERT_COLON; 138114443Snectar strlcat(output, label, size); 139101353Smike } else if (strcmp(comp, "severity") == 0 && sevname != NULL) { 140101353Smike INSERT_COLON; 141114443Snectar strlcat(output, sevinfo(sev), size); 142101353Smike } else if (strcmp(comp, "text") == 0 && text != MM_NULLTXT) { 143101353Smike INSERT_COLON; 144114443Snectar strlcat(output, text, size); 145101353Smike } else if (strcmp(comp, "action") == 0 && act != MM_NULLACT) { 146101353Smike INSERT_NEWLINE; 147114443Snectar strlcat(output, "TO FIX: ", size); 148114443Snectar strlcat(output, act, size); 149101353Smike } else if (strcmp(comp, "tag") == 0 && tag != MM_NULLTAG) { 150101353Smike INSERT_SPACE; 151114443Snectar strlcat(output, tag, size); 152101353Smike } 153101353Smike } 154101353Smike INSERT_NEWLINE; 155101353Smike return (output); 156101353Smike} 157101353Smike 158101403Smike/* 159101403Smike * Returns a component of a colon delimited string. NULL is returned to 160101403Smike * indicate that there are no remaining components. This function must be 161101403Smike * called until it returns NULL in order for the local state to be cleared. 162101403Smike */ 163101353Smikestatic char * 164101353Smikenextcomp(const char *msgverb) 165101353Smike{ 166101353Smike static char lmsgverb[MAX_MSGVERB], *state; 167101353Smike char *retval; 168101353Smike 169101353Smike if (*lmsgverb == '\0') { 170114443Snectar strlcpy(lmsgverb, msgverb, sizeof(lmsgverb)); 171101353Smike retval = strtok_r(lmsgverb, ":", &state); 172101353Smike } else { 173101353Smike retval = strtok_r(NULL, ":", &state); 174101353Smike } 175101353Smike if (retval == NULL) 176101353Smike *lmsgverb = '\0'; 177101353Smike return (retval); 178101353Smike} 179101353Smike 180101353Smikestatic const char * 181101353Smikesevinfo(int sev) 182101353Smike{ 183101353Smike 184101353Smike switch (sev) { 185101353Smike case MM_HALT: 186101353Smike return ("HALT"); 187101353Smike case MM_ERROR: 188101353Smike return ("ERROR"); 189101353Smike case MM_WARNING: 190101353Smike return ("WARNING"); 191101353Smike case MM_INFO: 192101353Smike return ("INFO"); 193101353Smike default: 194101353Smike return (NULL); 195101353Smike } 196101353Smike} 197101353Smike 198101353Smike/* 199101353Smike * Returns 1 if the msgverb list is valid, otherwise 0. 200101353Smike */ 201101353Smikestatic int 202101353Smikevalidmsgverb(const char *msgverb) 203101353Smike{ 204232007Sjilles const char *validlist = "label\0severity\0text\0action\0tag\0"; 205101353Smike char *msgcomp; 206232007Sjilles size_t len1, len2; 207232007Sjilles const char *p; 208232007Sjilles int equality; 209101353Smike 210101403Smike equality = 0; 211101353Smike while ((msgcomp = nextcomp(msgverb)) != NULL) { 212101403Smike equality--; 213232007Sjilles len1 = strlen(msgcomp); 214232007Sjilles for (p = validlist; (len2 = strlen(p)) != 0; p += len2 + 1) { 215232007Sjilles if (len1 == len2 && memcmp(msgcomp, p, len1) == 0) 216101403Smike equality++; 217101353Smike } 218101353Smike } 219101403Smike return (!equality); 220101353Smike} 221