1 /*- 2 * Copyright (c) 2002 Mike Barcroft <mike@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD: src/lib/libc/gen/fmtmsg.c,v 1.6 2009/11/08 14:02:54 brueffer Exp $ 27 */ 28 29 #include <fmtmsg.h> 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <string.h> 33 34 /* Default value for MSGVERB. */ 35 #define DFLT_MSGVERB "label:severity:text:action:tag" 36 37 /* Maximum valid size for a MSGVERB. */ 38 #define MAX_MSGVERB sizeof(DFLT_MSGVERB) 39 40 static char *printfmt(char *, long, const char *, int, const char *, 41 const char *, const char *); 42 static char *nextcomp(const char *); 43 static const char 44 *sevinfo(int); 45 static int validmsgverb(const char *); 46 47 static const char *validlist[] = { 48 "label", "severity", "text", "action", "tag", NULL 49 }; 50 51 int 52 fmtmsg(long class, const char *label, int sev, const char *text, 53 const char *action, const char *tag) 54 { 55 FILE *fp; 56 char *env, *msgverb, *output; 57 58 if (class & MM_PRINT) { 59 if ((env = getenv("MSGVERB")) != NULL && *env != '\0' && 60 strlen(env) <= strlen(DFLT_MSGVERB)) { 61 if ((msgverb = strdup(env)) == NULL) 62 return (MM_NOTOK); 63 else if (validmsgverb(msgverb) == 0) { 64 free(msgverb); 65 goto def; 66 } 67 } else { 68 def: 69 if ((msgverb = strdup(DFLT_MSGVERB)) == NULL) 70 return (MM_NOTOK); 71 } 72 output = printfmt(msgverb, class, label, sev, text, action, 73 tag); 74 if (output == NULL) { 75 free(msgverb); 76 return (MM_NOTOK); 77 } 78 if (*output != '\0') 79 fprintf(stderr, "%s", output); 80 free(msgverb); 81 free(output); 82 } 83 if (class & MM_CONSOLE) { 84 output = printfmt(DFLT_MSGVERB, class, label, sev, text, 85 action, tag); 86 if (output == NULL) 87 return (MM_NOCON); 88 if (*output != '\0') { 89 if ((fp = fopen("/dev/console", "a")) == NULL) { 90 free(output); 91 return (MM_NOCON); 92 } 93 fprintf(fp, "%s", output); 94 fclose(fp); 95 } 96 free(output); 97 } 98 return (MM_OK); 99 } 100 101 #define INSERT_COLON \ 102 if (*output != '\0') \ 103 strlcat(output, ": ", size) 104 #define INSERT_NEWLINE \ 105 if (*output != '\0') \ 106 strlcat(output, "\n", size) 107 #define INSERT_SPACE \ 108 if (*output != '\0') \ 109 strlcat(output, " ", size) 110 111 /* 112 * Returns NULL on memory allocation failure, otherwise returns a pointer to 113 * a newly malloc()'d output buffer. 114 */ 115 static char * 116 printfmt(char *msgverb, long class __unused, const char *label, int sev, 117 const char *text, const char *act, const char *tag) 118 { 119 size_t size; 120 char *comp, *output; 121 const char *sevname; 122 123 size = 32; 124 if (label != MM_NULLLBL) 125 size += strlen(label); 126 if ((sevname = sevinfo(sev)) != NULL) 127 size += strlen(sevname); 128 if (text != MM_NULLTXT) 129 size += strlen(text); 130 if (act != MM_NULLACT) 131 size += strlen(act); 132 if (tag != MM_NULLTAG) 133 size += strlen(tag); 134 135 if ((output = malloc(size)) == NULL) 136 return (NULL); 137 *output = '\0'; 138 while ((comp = nextcomp(msgverb)) != NULL) { 139 if (strcmp(comp, "label") == 0 && label != MM_NULLLBL) { 140 INSERT_COLON; 141 strlcat(output, label, size); 142 } else if (strcmp(comp, "severity") == 0 && sevname != NULL) { 143 INSERT_COLON; 144 strlcat(output, sevinfo(sev), size); 145 } else if (strcmp(comp, "text") == 0 && text != MM_NULLTXT) { 146 INSERT_COLON; 147 strlcat(output, text, size); 148 } else if (strcmp(comp, "action") == 0 && act != MM_NULLACT) { 149 INSERT_NEWLINE; 150 strlcat(output, "TO FIX: ", size); 151 strlcat(output, act, size); 152 } else if (strcmp(comp, "tag") == 0 && tag != MM_NULLTAG) { 153 INSERT_SPACE; 154 strlcat(output, tag, size); 155 } 156 } 157 INSERT_NEWLINE; 158 return (output); 159 } 160 161 /* 162 * Returns a component of a colon delimited string. NULL is returned to 163 * indicate that there are no remaining components. This function must be 164 * called until it returns NULL in order for the local state to be cleared. 165 */ 166 static char * 167 nextcomp(const char *msgverb) 168 { 169 static char lmsgverb[MAX_MSGVERB], *state; 170 char *retval; 171 172 if (*lmsgverb == '\0') { 173 strlcpy(lmsgverb, msgverb, sizeof(lmsgverb)); 174 retval = strtok_r(lmsgverb, ":", &state); 175 } else { 176 retval = strtok_r(NULL, ":", &state); 177 } 178 if (retval == NULL) 179 *lmsgverb = '\0'; 180 return (retval); 181 } 182 183 static const char * 184 sevinfo(int sev) 185 { 186 187 switch (sev) { 188 case MM_HALT: 189 return ("HALT"); 190 case MM_ERROR: 191 return ("ERROR"); 192 case MM_WARNING: 193 return ("WARNING"); 194 case MM_INFO: 195 return ("INFO"); 196 default: 197 return (NULL); 198 } 199 } 200 201 /* 202 * Returns 1 if the msgverb list is valid, otherwise 0. 203 */ 204 static int 205 validmsgverb(const char *msgverb) 206 { 207 char *msgcomp; 208 int i, equality; 209 210 equality = 0; 211 while ((msgcomp = nextcomp(msgverb)) != NULL) { 212 equality--; 213 for (i = 0; validlist[i] != NULL; i++) { 214 if (strcmp(msgcomp, validlist[i]) == 0) 215 equality++; 216 } 217 } 218 return (!equality); 219 } 220