1*9a513d96Schristos /* $NetBSD: fmtmsg.c,v 1.6 2014/09/18 13:58:20 christos Exp $ */
2734b2b9bSkleink
3734b2b9bSkleink /*-
4734b2b9bSkleink * Copyright (c) 1999 The NetBSD Foundation, Inc.
5734b2b9bSkleink * All rights reserved.
6734b2b9bSkleink *
7734b2b9bSkleink * This code is derived from software contributed to The NetBSD Foundation
8734b2b9bSkleink * by Klaus Klein.
9734b2b9bSkleink *
10734b2b9bSkleink * Redistribution and use in source and binary forms, with or without
11734b2b9bSkleink * modification, are permitted provided that the following conditions
12734b2b9bSkleink * are met:
13734b2b9bSkleink * 1. Redistributions of source code must retain the above copyright
14734b2b9bSkleink * notice, this list of conditions and the following disclaimer.
15734b2b9bSkleink * 2. Redistributions in binary form must reproduce the above copyright
16734b2b9bSkleink * notice, this list of conditions and the following disclaimer in the
17734b2b9bSkleink * documentation and/or other materials provided with the distribution.
18734b2b9bSkleink *
19734b2b9bSkleink * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20734b2b9bSkleink * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21734b2b9bSkleink * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22734b2b9bSkleink * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23734b2b9bSkleink * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24734b2b9bSkleink * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25734b2b9bSkleink * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26734b2b9bSkleink * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27734b2b9bSkleink * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28734b2b9bSkleink * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29734b2b9bSkleink * POSSIBILITY OF SUCH DAMAGE.
30734b2b9bSkleink */
31734b2b9bSkleink
32734b2b9bSkleink #include <sys/cdefs.h>
33d5cfef41Skleink #if defined(LIBC_SCCS) && !defined(lint)
34*9a513d96Schristos __RCSID("$NetBSD: fmtmsg.c,v 1.6 2014/09/18 13:58:20 christos Exp $");
35d5cfef41Skleink #endif /* LIBC_SCCS and not lint */
36d5cfef41Skleink
37734b2b9bSkleink #include <fmtmsg.h>
38734b2b9bSkleink #include <paths.h>
39734b2b9bSkleink #include <stdio.h>
40734b2b9bSkleink #include <stdlib.h>
41734b2b9bSkleink #include <string.h>
42734b2b9bSkleink
43cf884af3Smatt static unsigned int msgverb(const char *);
44cf884af3Smatt static const char * severity2str(int);
45cf884af3Smatt static int writeit(FILE *, unsigned int, const char *,
46734b2b9bSkleink const char *, const char *, const char *,
47cf884af3Smatt const char *);
48734b2b9bSkleink
49734b2b9bSkleink #define MM_VERBLABEL 0x01U
50734b2b9bSkleink #define MM_VERBSEVERITY 0x02U
51734b2b9bSkleink #define MM_VERBTEXT 0x04U
52734b2b9bSkleink #define MM_VERBACTION 0x08U
53734b2b9bSkleink #define MM_VERBTAG 0x10U
54734b2b9bSkleink #define MM_VERBALL \
55734b2b9bSkleink (MM_VERBLABEL | MM_VERBSEVERITY | MM_VERBTEXT | MM_VERBACTION | \
56734b2b9bSkleink MM_VERBTAG)
57734b2b9bSkleink
58734b2b9bSkleink static const struct keyword {
59734b2b9bSkleink size_t len; /* strlen(keyword) */
60734b2b9bSkleink const char * const keyword;
61734b2b9bSkleink } keywords[] = {
62734b2b9bSkleink { 5, "label" }, /* log2(MM_VERBLABEL) */
63734b2b9bSkleink { 8, "severity" }, /* ... */
64734b2b9bSkleink { 4, "text" },
65734b2b9bSkleink { 6, "action" },
66734b2b9bSkleink { 3, "tag" } /* log2(MM_VERBTAG) */
67734b2b9bSkleink };
68734b2b9bSkleink
69734b2b9bSkleink static const size_t nkeywords = sizeof (keywords) / sizeof (keywords[0]);
70734b2b9bSkleink
71734b2b9bSkleink /*
72734b2b9bSkleink * Convert a colon-separated list of known keywords to a set of MM_VERB*
73734b2b9bSkleink * flags, defaulting to `all' if not set, empty, or in presence of unknown
74734b2b9bSkleink * keywords.
75734b2b9bSkleink */
76734b2b9bSkleink static unsigned int
msgverb(const char * str)77cf884af3Smatt msgverb(const char *str)
78734b2b9bSkleink {
7937dfab8aSthorpej u_int i;
80734b2b9bSkleink unsigned int result;
81734b2b9bSkleink
82734b2b9bSkleink if (str == NULL)
83734b2b9bSkleink return (MM_VERBALL);
84734b2b9bSkleink
85734b2b9bSkleink result = 0;
86734b2b9bSkleink while (*str != '\0') {
87734b2b9bSkleink for (i = 0; i < nkeywords; i++) {
88734b2b9bSkleink if (memcmp(str, keywords[i].keyword, keywords[i].len)
89734b2b9bSkleink == 0 &&
90734b2b9bSkleink (*(str + keywords[i].len) == ':' ||
91734b2b9bSkleink *(str + keywords[i].len) == '\0'))
92734b2b9bSkleink break;
93734b2b9bSkleink }
94734b2b9bSkleink if (i == nkeywords) {
95734b2b9bSkleink result = MM_VERBALL;
96734b2b9bSkleink break;
97734b2b9bSkleink }
98734b2b9bSkleink
99734b2b9bSkleink result |= (1 << i);
100734b2b9bSkleink if (*(str += keywords[i].len) == ':')
101734b2b9bSkleink str++; /* Advance */
102734b2b9bSkleink }
103734b2b9bSkleink if (result == 0)
104734b2b9bSkleink result = MM_VERBALL;
105734b2b9bSkleink
106734b2b9bSkleink return (result);
107734b2b9bSkleink }
108734b2b9bSkleink
109cf884af3Smatt static const char severities[][8] = {
110734b2b9bSkleink "", /* MM_NONE */
111734b2b9bSkleink "HALT",
112734b2b9bSkleink "ERROR",
113734b2b9bSkleink "WARNING",
114734b2b9bSkleink "INFO"
115734b2b9bSkleink };
116734b2b9bSkleink
117734b2b9bSkleink static const size_t nseverities = sizeof (severities) / sizeof (severities[0]);
118734b2b9bSkleink
119734b2b9bSkleink /*
120734b2b9bSkleink * Returns the string representation associated with the numerical severity
121734b2b9bSkleink * value, defaulting to NULL for an unknown value.
122734b2b9bSkleink */
123734b2b9bSkleink static const char *
severity2str(int severity)124cf884af3Smatt severity2str(int severity)
125734b2b9bSkleink {
126734b2b9bSkleink const char *result;
127734b2b9bSkleink
12837dfab8aSthorpej if (severity >= 0 &&
12937dfab8aSthorpej (u_int) severity < nseverities)
130734b2b9bSkleink result = severities[severity];
131734b2b9bSkleink else
132734b2b9bSkleink result = NULL;
133734b2b9bSkleink
134734b2b9bSkleink return (result);
135734b2b9bSkleink }
136734b2b9bSkleink
137734b2b9bSkleink /*
138734b2b9bSkleink * Format and write the message to the given stream, selecting those
139734b2b9bSkleink * components displayed from msgverb, returning the number of characters
140734b2b9bSkleink * written, or a negative value in case of an error.
141734b2b9bSkleink */
142734b2b9bSkleink static int
writeit(FILE * stream,unsigned int which,const char * label,const char * sevstr,const char * text,const char * action,const char * tag)143cf884af3Smatt writeit(FILE *stream, unsigned int which, const char *label,
144cf884af3Smatt const char *sevstr, const char *text, const char *action,
145cf884af3Smatt const char *tag)
146734b2b9bSkleink {
147734b2b9bSkleink int nwritten;
148734b2b9bSkleink
149734b2b9bSkleink nwritten = fprintf(stream, "%s%s%s%s%s%s%s%s%s%s%s",
150734b2b9bSkleink ((which & MM_VERBLABEL) && label != MM_NULLLBL) ?
151734b2b9bSkleink label : "",
152734b2b9bSkleink ((which & MM_VERBLABEL) && label != MM_NULLLBL) ?
153734b2b9bSkleink ": " : "",
154734b2b9bSkleink (which & MM_VERBSEVERITY) ?
155734b2b9bSkleink sevstr : "",
156734b2b9bSkleink (which & MM_VERBSEVERITY) ?
157734b2b9bSkleink ": " : "",
158734b2b9bSkleink ((which & MM_VERBTEXT) && text != MM_NULLTXT) ?
159734b2b9bSkleink text : "",
160734b2b9bSkleink ((which & MM_VERBLABEL) && label != MM_NULLLBL) ||
161734b2b9bSkleink ((which & MM_VERBSEVERITY)) ||
162734b2b9bSkleink ((which & MM_VERBTEXT) && text != MM_NULLTXT) ?
163734b2b9bSkleink "\n" : "",
164734b2b9bSkleink ((which & MM_VERBACTION) && action != MM_NULLACT) ?
165734b2b9bSkleink "TO FIX: " : "",
166734b2b9bSkleink ((which & MM_VERBACTION) && action != MM_NULLACT) ?
167734b2b9bSkleink action : "",
168734b2b9bSkleink ((which & MM_VERBACTION) && label != MM_NULLACT) ?
169734b2b9bSkleink " " : "",
170734b2b9bSkleink ((which & MM_VERBTAG) && tag != MM_NULLTAG) ?
171734b2b9bSkleink tag : "",
172734b2b9bSkleink ((which & MM_VERBACTION) && action != MM_NULLACT) ||
173734b2b9bSkleink ((which & MM_VERBTAG) && tag != MM_NULLTAG) ?
174734b2b9bSkleink "\n" : "");
175734b2b9bSkleink
176734b2b9bSkleink return (nwritten);
177734b2b9bSkleink }
178734b2b9bSkleink
179734b2b9bSkleink int
fmtmsg(long classification,const char * label,int severity,const char * text,const char * action,const char * tag)180cf884af3Smatt fmtmsg(long classification, const char *label, int severity,
181cf884af3Smatt const char *text, const char *action, const char *tag)
182734b2b9bSkleink {
183734b2b9bSkleink FILE *console;
184734b2b9bSkleink const char *p, *sevstr;
185734b2b9bSkleink int result;
186734b2b9bSkleink
187734b2b9bSkleink /* Validate label constraints, if not null. */
188734b2b9bSkleink if (label != MM_NULLLBL) {
189734b2b9bSkleink /*
190734b2b9bSkleink * Two fields, separated by a colon. The first field is up to
191734b2b9bSkleink * 10 bytes, the second is up to 14 bytes.
192734b2b9bSkleink */
193734b2b9bSkleink p = strchr(label, ':');
194734b2b9bSkleink if (p == NULL || p - label > 10 || strlen(p + 1) > 14)
195734b2b9bSkleink return (MM_NOTOK);
196734b2b9bSkleink }
197734b2b9bSkleink /* Validate severity argument. */
198734b2b9bSkleink if ((sevstr = severity2str(severity)) == NULL)
199734b2b9bSkleink return (MM_NOTOK);
200734b2b9bSkleink
201734b2b9bSkleink /*
202734b2b9bSkleink * Fact in search for a better place: XSH5 does not define any
203734b2b9bSkleink * functionality for `classification' bits other than the display
204734b2b9bSkleink * subclassification.
205734b2b9bSkleink */
206734b2b9bSkleink
207734b2b9bSkleink result = 0;
208734b2b9bSkleink
209734b2b9bSkleink if (classification & MM_PRINT) {
210734b2b9bSkleink if (writeit(stderr, msgverb(getenv("MSGVERB")),
211734b2b9bSkleink label, sevstr, text, action, tag) < 0)
212734b2b9bSkleink result |= MM_NOMSG;
213734b2b9bSkleink }
214734b2b9bSkleink /* Similar to MM_PRINT but ignoring $MSGVERB. */
215734b2b9bSkleink if (classification & MM_CONSOLE) {
216*9a513d96Schristos if ((console = fopen(_PATH_CONSOLE, "we")) != NULL) {
217734b2b9bSkleink if (writeit(console, MM_VERBALL,
218734b2b9bSkleink label, sevstr, text, action, tag) < 0)
219734b2b9bSkleink result |= MM_NOCON;
220734b2b9bSkleink /*
221734b2b9bSkleink * Ignore result: does not constitute ``generate a
222734b2b9bSkleink * console message.''
223734b2b9bSkleink */
224734b2b9bSkleink (void)fclose(console);
225734b2b9bSkleink } else {
226734b2b9bSkleink result |= MM_NOCON;
227734b2b9bSkleink }
228734b2b9bSkleink }
229734b2b9bSkleink
230734b2b9bSkleink if (result == (MM_NOMSG | MM_NOCON))
231734b2b9bSkleink result = MM_NOTOK;
232734b2b9bSkleink
233734b2b9bSkleink return (result == 0 ? MM_OK : result);
234734b2b9bSkleink }
235