fmtmsg.c revision 101353
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
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: head/lib/libc/gen/fmtmsg.c 101353 2002-08-05 06:49:58Z mike $");
29
30#include <fmtmsg.h>
31#include <stdio.h>
32#include <stdlib.h>
33#include <string.h>
34
35/* Default value for MSGVERB. */
36#define	DFLT_MSGVERB	"label:severity:text:action:tag"
37
38/* Maximum valid size for a MSGVERB. */
39#define	MAX_MSGVERB	sizeof(DFLT_MSGVERB)
40
41static char	*printfmt(char *, long, const char *, int, const char *,
42		    const char *, const char *);
43static char	*nextcomp(const char *);
44static const char
45		*sevinfo(int);
46static int	 validmsgverb(const char *);
47
48static const char *validlist[] = {
49	"label", "severity", "text", "action", "tag", NULL
50};
51
52int
53fmtmsg(long class, const char *label, int sev, const char *text,
54    const char *action, const char *tag)
55{
56	FILE *fp;
57	char *env, *msgverb, *output;
58
59	if (class & MM_PRINT) {
60		if ((env = getenv("MSGVERB")) != NULL && *env != '\0' &&
61		    strlen(env) <= strlen(DFLT_MSGVERB)) {
62			if ((msgverb = strdup(env)) == NULL)
63				return (MM_NOTOK);
64			else if (validmsgverb(msgverb) == 0)
65				goto def;
66		} else {
67def:
68			if ((msgverb = strdup(DFLT_MSGVERB)) == NULL)
69				return (MM_NOTOK);
70		}
71		output = printfmt(msgverb, class, label, sev, text, action,
72		    tag);
73		if (output == NULL)
74			return (MM_NOTOK);
75		if (*output != '\0')
76			fprintf(stderr, "%s", output);
77		free(msgverb);
78		free(output);
79	}
80	if (class & MM_CONSOLE) {
81		output = printfmt(DFLT_MSGVERB, class, label, sev, text,
82		    action, tag);
83		if (output == NULL)
84			return (MM_NOCON);
85		if (*output != '\0') {
86			if ((fp = fopen("/dev/console", "a")) == NULL) {
87				free(output);
88				return (MM_NOCON);
89			}
90			fprintf(fp, "%s", output);
91			fclose(fp);
92		}
93		free(output);
94	}
95	return (MM_OK);
96}
97
98#define INSERT_COLON							\
99	if (*output != '\0')						\
100		strlcat(output, ": ", size)
101#define INSERT_NEWLINE							\
102	if (*output != '\0')						\
103		strlcat(output, "\n", size)
104#define INSERT_SPACE							\
105	if (*output != '\0')						\
106		strlcat(output, " ", size)
107
108/*
109 * Returns NULL on memory allocation failure, otherwise returns a pointer to
110 * a newly malloc()'d output buffer.
111 */
112static char *
113printfmt(char *msgverb, long class, const char *label, int sev,
114    const char *text, const char *act, const char *tag)
115{
116	size_t size;
117	char *comp, *output;
118	const char *sevname;
119
120	size = 32;
121	if (label != MM_NULLLBL)
122		size += strlen(label);
123	if ((sevname = sevinfo(sev)) != NULL)
124		size += strlen(sevname);
125	if (text != MM_NULLTXT)
126		size += strlen(text);
127	if (text != MM_NULLACT)
128		size += strlen(act);
129	if (tag != MM_NULLTAG)
130		size += strlen(tag);
131
132	if ((output = malloc(size)) == NULL)
133		return (NULL);
134	*output = '\0';
135	while ((comp = nextcomp(msgverb)) != NULL) {
136		if (strcmp(comp, "label") == 0 && label != MM_NULLLBL) {
137			INSERT_COLON;
138			strlcat(output, label, size);
139		} else if (strcmp(comp, "severity") == 0 && sevname != NULL) {
140			INSERT_COLON;
141			strlcat(output, sevinfo(sev), size);
142		} else if (strcmp(comp, "text") == 0 && text != MM_NULLTXT) {
143			INSERT_COLON;
144			strlcat(output, text, size);
145		} else if (strcmp(comp, "action") == 0 && act != MM_NULLACT) {
146			INSERT_NEWLINE;
147			strlcat(output, "TO FIX: ", size);
148			strlcat(output, act, size);
149		} else if (strcmp(comp, "tag") == 0 && tag != MM_NULLTAG) {
150			INSERT_SPACE;
151			strlcat(output, tag, size);
152		}
153	}
154	INSERT_NEWLINE;
155	return (output);
156}
157
158static char *
159nextcomp(const char *msgverb)
160{
161	static char lmsgverb[MAX_MSGVERB], *state;
162	char *retval;
163
164	if (*lmsgverb == '\0') {
165		strlcpy(lmsgverb, msgverb, sizeof(lmsgverb));
166		retval = strtok_r(lmsgverb, ":", &state);
167	} else {
168		retval = strtok_r(NULL, ":", &state);
169	}
170	if (retval == NULL)
171		*lmsgverb = '\0';
172	return (retval);
173}
174
175static const char *
176sevinfo(int sev)
177{
178
179	switch (sev) {
180	case MM_HALT:
181		return ("HALT");
182	case MM_ERROR:
183		return ("ERROR");
184	case MM_WARNING:
185		return ("WARNING");
186	case MM_INFO:
187		return ("INFO");
188	default:
189		return (NULL);
190	}
191}
192
193/*
194 * Returns 1 if the msgverb list is valid, otherwise 0.
195 */
196static int
197validmsgverb(const char *msgverb)
198{
199	char *msgcomp;
200	const char *validcomp;
201
202	while ((msgcomp = nextcomp(msgverb)) != NULL) {
203		if (*msgcomp == '\0')
204			return (0);
205		for (validcomp = *validlist;
206		    validcomp != NULL; validcomp++) {
207			if (strcmp(msgcomp, validcomp) == 0)
208				break;
209		}
210		if (validcomp == NULL)
211			return (0);
212	}
213	return (1);
214}
215