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