fmtutils.c revision 356341
1/*
2 * Copyright (c) 1993, 1994, 1995, 1996, 1997, 1998
3 *	The Regents of the University of California.  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 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by the Computer Systems
16 *	Engineering Group at Lawrence Berkeley Laboratory.
17 * 4. Neither the name of the University nor of the Laboratory may be used
18 *    to endorse or promote products derived from this software without
19 *    specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34/*
35 * Utilities for message formatting used both by libpcap and rpcapd.
36 */
37
38#ifdef HAVE_CONFIG_H
39#include <config.h>
40#endif
41
42#include "ftmacros.h"
43
44#include <stddef.h>
45#include <stdarg.h>
46#include <stdio.h>
47#include <string.h>
48#include <errno.h>
49
50#include <pcap/pcap.h>
51
52#include "portability.h"
53
54#include "fmtutils.h"
55
56/*
57 * Generate an error message based on a format, arguments, and an
58 * errno, with a message for the errno after the formatted output.
59 */
60void
61pcap_fmt_errmsg_for_errno(char *errbuf, size_t errbuflen, int errnum,
62    const char *fmt, ...)
63{
64	va_list ap;
65	size_t msglen;
66	char *p;
67	size_t errbuflen_remaining;
68
69	va_start(ap, fmt);
70	pcap_vsnprintf(errbuf, errbuflen, fmt, ap);
71	va_end(ap);
72	msglen = strlen(errbuf);
73
74	/*
75	 * Do we have enough space to append ": "?
76	 * Including the terminating '\0', that's 3 bytes.
77	 */
78	if (msglen + 3 > errbuflen) {
79		/* No - just give them what we've produced. */
80		return;
81	}
82	p = errbuf + msglen;
83	errbuflen_remaining = errbuflen - msglen;
84	*p++ = ':';
85	*p++ = ' ';
86	*p = '\0';
87	msglen += 2;
88	errbuflen_remaining -= 2;
89
90	/*
91	 * Now append the string for the error code.
92	 */
93#if defined(HAVE_STRERROR_S)
94	/*
95	 * We have a Windows-style strerror_s().
96	 */
97	errno_t err = strerror_s(p, errbuflen_remaining, errnum);
98	if (err != 0) {
99		/*
100		 * It doesn't appear to be documented anywhere obvious
101		 * what the error returns from strerror_s().
102		 */
103		pcap_snprintf(p, errbuflen_remaining, "Error %d", errnum);
104	}
105#elif defined(HAVE_GNU_STRERROR_R)
106	/*
107	 * We have a GNU-style strerror_r(), which is *not* guaranteed to
108	 * do anything to the buffer handed to it, and which returns a
109	 * pointer to the error string, which may or may not be in
110	 * the buffer.
111	 *
112	 * It is, however, guaranteed to succeed.
113	 */
114	char strerror_buf[PCAP_ERRBUF_SIZE];
115	char *errstring = strerror_r(errnum, strerror_buf, PCAP_ERRBUF_SIZE);
116	pcap_snprintf(p, errbuflen_remaining, "%s", errstring);
117#elif defined(HAVE_POSIX_STRERROR_R)
118	/*
119	 * We have a POSIX-style strerror_r(), which is guaranteed to fill
120	 * in the buffer, but is not guaranteed to succeed.
121	 */
122	int err = strerror_r(errnum, p, errbuflen_remaining);
123	if (err == EINVAL) {
124		/*
125		 * UNIX 03 says this isn't guaranteed to produce a
126		 * fallback error message.
127		 */
128		pcap_snprintf(p, errbuflen_remaining, "Unknown error: %d",
129		    errnum);
130	} else if (err == ERANGE) {
131		/*
132		 * UNIX 03 says this isn't guaranteed to produce a
133		 * fallback error message.
134		 */
135		pcap_snprintf(p, errbuflen_remaining,
136		    "Message for error %d is too long", errnum);
137	}
138#else
139	/*
140	 * We have neither strerror_s() nor strerror_r(), so we're
141	 * stuck with using pcap_strerror().
142	 */
143	pcap_snprintf(p, errbuflen_remaining, "%s", pcap_strerror(errnum));
144#endif
145}
146
147#ifdef _WIN32
148/*
149 * Generate an error message based on a format, arguments, and a
150 * Win32 error, with a message for the Win32 error after the formatted output.
151 */
152void
153pcap_fmt_errmsg_for_win32_err(char *errbuf, size_t errbuflen, DWORD errnum,
154    const char *fmt, ...)
155{
156	va_list ap;
157	size_t msglen;
158	char *p;
159	size_t errbuflen_remaining;
160	DWORD retval;
161	char win32_errbuf[PCAP_ERRBUF_SIZE+1];
162
163	va_start(ap, fmt);
164	pcap_vsnprintf(errbuf, errbuflen, fmt, ap);
165	va_end(ap);
166	msglen = strlen(errbuf);
167
168	/*
169	 * Do we have enough space to append ": "?
170	 * Including the terminating '\0', that's 3 bytes.
171	 */
172	if (msglen + 3 > errbuflen) {
173		/* No - just give them what we've produced. */
174		return;
175	}
176	p = errbuf + msglen;
177	errbuflen_remaining = errbuflen - msglen;
178	*p++ = ':';
179	*p++ = ' ';
180	*p = '\0';
181	msglen += 2;
182	errbuflen_remaining -= 2;
183
184	/*
185	 * Now append the string for the error code.
186	 *
187	 * XXX - what language ID to use?
188	 *
189	 * For UN*Xes, pcap_strerror() may or may not return localized
190	 * strings.
191	 *
192	 * We currently don't have localized messages for libpcap, but
193	 * we might want to do so.  On the other hand, if most of these
194	 * messages are going to be read by libpcap developers and
195	 * perhaps by developers of libpcap-based applications, English
196	 * might be a better choice, so the developer doesn't have to
197	 * get the message translated if it's in a language they don't
198	 * happen to understand.
199	 */
200	retval = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS|FORMAT_MESSAGE_MAX_WIDTH_MASK,
201	    NULL, errnum, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
202	    win32_errbuf, PCAP_ERRBUF_SIZE, NULL);
203	if (retval == 0) {
204		/*
205		 * Failed.
206		 */
207		pcap_snprintf(p, errbuflen_remaining,
208		    "Couldn't get error message for error (%lu)", errnum);
209		return;
210	}
211
212	pcap_snprintf(p, errbuflen_remaining, "%s (%lu)", win32_errbuf, errnum);
213}
214#endif
215