1 /* $NetBSD: fmtmsg.c,v 1.3 2002/11/11 06:31:14 thorpej Exp $ */ 2 3 /*- 4 * Copyright (c) 1999 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Klaus Klein. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 #include <sys/cdefs.h> 40 #if defined(LIBC_SCCS) && !defined(lint) 41 __RCSID("$NetBSD: fmtmsg.c,v 1.3 2002/11/11 06:31:14 thorpej Exp $"); 42 #endif /* LIBC_SCCS and not lint */ 43 44 #include <fmtmsg.h> 45 #include <paths.h> 46 #include <stdio.h> 47 #include <stdlib.h> 48 #include <string.h> 49 50 static unsigned int msgverb __P((const char *)); 51 static const char * severity2str __P((int)); 52 static int writeit __P((FILE *, unsigned int, const char *, 53 const char *, const char *, const char *, 54 const char *)); 55 56 #define MM_VERBLABEL 0x01U 57 #define MM_VERBSEVERITY 0x02U 58 #define MM_VERBTEXT 0x04U 59 #define MM_VERBACTION 0x08U 60 #define MM_VERBTAG 0x10U 61 #define MM_VERBALL \ 62 (MM_VERBLABEL | MM_VERBSEVERITY | MM_VERBTEXT | MM_VERBACTION | \ 63 MM_VERBTAG) 64 65 static const struct keyword { 66 size_t len; /* strlen(keyword) */ 67 const char * const keyword; 68 } keywords[] = { 69 { 5, "label" }, /* log2(MM_VERBLABEL) */ 70 { 8, "severity" }, /* ... */ 71 { 4, "text" }, 72 { 6, "action" }, 73 { 3, "tag" } /* log2(MM_VERBTAG) */ 74 }; 75 76 static const size_t nkeywords = sizeof (keywords) / sizeof (keywords[0]); 77 78 /* 79 * Convert a colon-separated list of known keywords to a set of MM_VERB* 80 * flags, defaulting to `all' if not set, empty, or in presence of unknown 81 * keywords. 82 */ 83 static unsigned int 84 msgverb(str) 85 const char *str; 86 { 87 u_int i; 88 unsigned int result; 89 90 if (str == NULL) 91 return (MM_VERBALL); 92 93 result = 0; 94 while (*str != '\0') { 95 for (i = 0; i < nkeywords; i++) { 96 if (memcmp(str, keywords[i].keyword, keywords[i].len) 97 == 0 && 98 (*(str + keywords[i].len) == ':' || 99 *(str + keywords[i].len) == '\0')) 100 break; 101 } 102 if (i == nkeywords) { 103 result = MM_VERBALL; 104 break; 105 } 106 107 result |= (1 << i); 108 if (*(str += keywords[i].len) == ':') 109 str++; /* Advance */ 110 } 111 if (result == 0) 112 result = MM_VERBALL; 113 114 return (result); 115 } 116 117 static const char * const severities[] = { 118 "", /* MM_NONE */ 119 "HALT", 120 "ERROR", 121 "WARNING", 122 "INFO" 123 }; 124 125 static const size_t nseverities = sizeof (severities) / sizeof (severities[0]); 126 127 /* 128 * Returns the string representation associated with the numerical severity 129 * value, defaulting to NULL for an unknown value. 130 */ 131 static const char * 132 severity2str(severity) 133 int severity; 134 { 135 const char *result; 136 137 if (severity >= 0 && 138 (u_int) severity < nseverities) 139 result = severities[severity]; 140 else 141 result = NULL; 142 143 return (result); 144 } 145 146 /* 147 * Format and write the message to the given stream, selecting those 148 * components displayed from msgverb, returning the number of characters 149 * written, or a negative value in case of an error. 150 */ 151 static int 152 writeit(stream, which, label, sevstr, text, action, tag) 153 FILE *stream; 154 unsigned int which; 155 const char *label; 156 const char *sevstr; 157 const char *text; 158 const char *action; 159 const char *tag; 160 { 161 int nwritten; 162 163 nwritten = fprintf(stream, "%s%s%s%s%s%s%s%s%s%s%s", 164 ((which & MM_VERBLABEL) && label != MM_NULLLBL) ? 165 label : "", 166 ((which & MM_VERBLABEL) && label != MM_NULLLBL) ? 167 ": " : "", 168 (which & MM_VERBSEVERITY) ? 169 sevstr : "", 170 (which & MM_VERBSEVERITY) ? 171 ": " : "", 172 ((which & MM_VERBTEXT) && text != MM_NULLTXT) ? 173 text : "", 174 ((which & MM_VERBLABEL) && label != MM_NULLLBL) || 175 ((which & MM_VERBSEVERITY)) || 176 ((which & MM_VERBTEXT) && text != MM_NULLTXT) ? 177 "\n" : "", 178 ((which & MM_VERBACTION) && action != MM_NULLACT) ? 179 "TO FIX: " : "", 180 ((which & MM_VERBACTION) && action != MM_NULLACT) ? 181 action : "", 182 ((which & MM_VERBACTION) && label != MM_NULLACT) ? 183 " " : "", 184 ((which & MM_VERBTAG) && tag != MM_NULLTAG) ? 185 tag : "", 186 ((which & MM_VERBACTION) && action != MM_NULLACT) || 187 ((which & MM_VERBTAG) && tag != MM_NULLTAG) ? 188 "\n" : ""); 189 190 return (nwritten); 191 } 192 193 int 194 fmtmsg(classification, label, severity, text, action, tag) 195 long classification; 196 const char *label; 197 int severity; 198 const char *text; 199 const char *action; 200 const char *tag; 201 { 202 FILE *console; 203 const char *p, *sevstr; 204 int result; 205 206 /* Validate label constraints, if not null. */ 207 if (label != MM_NULLLBL) { 208 /* 209 * Two fields, separated by a colon. The first field is up to 210 * 10 bytes, the second is up to 14 bytes. 211 */ 212 p = strchr(label, ':'); 213 if (p == NULL || p - label > 10 || strlen(p + 1) > 14) 214 return (MM_NOTOK); 215 } 216 /* Validate severity argument. */ 217 if ((sevstr = severity2str(severity)) == NULL) 218 return (MM_NOTOK); 219 220 /* 221 * Fact in search for a better place: XSH5 does not define any 222 * functionality for `classification' bits other than the display 223 * subclassification. 224 */ 225 226 result = 0; 227 228 if (classification & MM_PRINT) { 229 if (writeit(stderr, msgverb(getenv("MSGVERB")), 230 label, sevstr, text, action, tag) < 0) 231 result |= MM_NOMSG; 232 } 233 /* Similar to MM_PRINT but ignoring $MSGVERB. */ 234 if (classification & MM_CONSOLE) { 235 if ((console = fopen(_PATH_CONSOLE, "w")) != NULL) { 236 if (writeit(console, MM_VERBALL, 237 label, sevstr, text, action, tag) < 0) 238 result |= MM_NOCON; 239 /* 240 * Ignore result: does not constitute ``generate a 241 * console message.'' 242 */ 243 (void)fclose(console); 244 } else { 245 result |= MM_NOCON; 246 } 247 } 248 249 if (result == (MM_NOMSG | MM_NOCON)) 250 result = MM_NOTOK; 251 252 return (result == 0 ? MM_OK : result); 253 } 254