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