13a289941SAaron LI /*
23a289941SAaron LI * Copyright (c) 1993, 1994, 1995, 1996, 1997, 1998
33a289941SAaron LI * The Regents of the University of California. All rights reserved.
43a289941SAaron LI *
53a289941SAaron LI * Redistribution and use in source and binary forms, with or without
63a289941SAaron LI * modification, are permitted provided that the following conditions
73a289941SAaron LI * are met:
83a289941SAaron LI * 1. Redistributions of source code must retain the above copyright
93a289941SAaron LI * notice, this list of conditions and the following disclaimer.
103a289941SAaron LI * 2. Redistributions in binary form must reproduce the above copyright
113a289941SAaron LI * notice, this list of conditions and the following disclaimer in the
123a289941SAaron LI * documentation and/or other materials provided with the distribution.
133a289941SAaron LI * 3. All advertising materials mentioning features or use of this software
143a289941SAaron LI * must display the following acknowledgement:
153a289941SAaron LI * This product includes software developed by the Computer Systems
163a289941SAaron LI * Engineering Group at Lawrence Berkeley Laboratory.
173a289941SAaron LI * 4. Neither the name of the University nor of the Laboratory may be used
183a289941SAaron LI * to endorse or promote products derived from this software without
193a289941SAaron LI * specific prior written permission.
203a289941SAaron LI *
213a289941SAaron LI * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
223a289941SAaron LI * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
233a289941SAaron LI * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
243a289941SAaron LI * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
253a289941SAaron LI * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
263a289941SAaron LI * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
273a289941SAaron LI * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
283a289941SAaron LI * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
293a289941SAaron LI * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
303a289941SAaron LI * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
313a289941SAaron LI * SUCH DAMAGE.
323a289941SAaron LI */
333a289941SAaron LI
343a289941SAaron LI /*
353a289941SAaron LI * Utilities for message formatting used both by libpcap and rpcapd.
363a289941SAaron LI */
373a289941SAaron LI
383a289941SAaron LI #ifdef HAVE_CONFIG_H
393a289941SAaron LI #include <config.h>
403a289941SAaron LI #endif
413a289941SAaron LI
423a289941SAaron LI #include "ftmacros.h"
433a289941SAaron LI
443a289941SAaron LI #include <stddef.h>
453a289941SAaron LI #include <stdarg.h>
463a289941SAaron LI #include <stdio.h>
473a289941SAaron LI #include <string.h>
483a289941SAaron LI #include <errno.h>
493a289941SAaron LI
50*ea16f64eSAntonio Huete Jimenez #include "pcap-int.h"
513a289941SAaron LI
523a289941SAaron LI #include "portability.h"
533a289941SAaron LI
543a289941SAaron LI #include "fmtutils.h"
553a289941SAaron LI
56*ea16f64eSAntonio Huete Jimenez #ifdef _WIN32
57*ea16f64eSAntonio Huete Jimenez #include "charconv.h"
58*ea16f64eSAntonio Huete Jimenez #endif
59*ea16f64eSAntonio Huete Jimenez
60*ea16f64eSAntonio Huete Jimenez /*
61*ea16f64eSAntonio Huete Jimenez * Set the encoding.
62*ea16f64eSAntonio Huete Jimenez */
63*ea16f64eSAntonio Huete Jimenez #ifdef _WIN32
64*ea16f64eSAntonio Huete Jimenez /*
65*ea16f64eSAntonio Huete Jimenez * True if we shouold use UTF-8.
66*ea16f64eSAntonio Huete Jimenez */
67*ea16f64eSAntonio Huete Jimenez static int use_utf_8;
68*ea16f64eSAntonio Huete Jimenez
69*ea16f64eSAntonio Huete Jimenez void
pcap_fmt_set_encoding(unsigned int opts)70*ea16f64eSAntonio Huete Jimenez pcap_fmt_set_encoding(unsigned int opts)
71*ea16f64eSAntonio Huete Jimenez {
72*ea16f64eSAntonio Huete Jimenez if (opts == PCAP_CHAR_ENC_UTF_8)
73*ea16f64eSAntonio Huete Jimenez use_utf_8 = 1;
74*ea16f64eSAntonio Huete Jimenez }
75*ea16f64eSAntonio Huete Jimenez #else
76*ea16f64eSAntonio Huete Jimenez void
pcap_fmt_set_encoding(unsigned int opts _U_)77*ea16f64eSAntonio Huete Jimenez pcap_fmt_set_encoding(unsigned int opts _U_)
78*ea16f64eSAntonio Huete Jimenez {
79*ea16f64eSAntonio Huete Jimenez /*
80*ea16f64eSAntonio Huete Jimenez * Nothing to do here.
81*ea16f64eSAntonio Huete Jimenez */
82*ea16f64eSAntonio Huete Jimenez }
83*ea16f64eSAntonio Huete Jimenez #endif
84*ea16f64eSAntonio Huete Jimenez
85*ea16f64eSAntonio Huete Jimenez #ifdef _WIN32
86*ea16f64eSAntonio Huete Jimenez /*
87*ea16f64eSAntonio Huete Jimenez * Convert a null-terminated UTF-16LE string to UTF-8, putting it into
88*ea16f64eSAntonio Huete Jimenez * a buffer starting at the specified location and stopping if we go
89*ea16f64eSAntonio Huete Jimenez * past the specified size. This will only put out complete UTF-8
90*ea16f64eSAntonio Huete Jimenez * sequences.
91*ea16f64eSAntonio Huete Jimenez *
92*ea16f64eSAntonio Huete Jimenez * We do this ourselves because Microsoft doesn't offer a "convert and
93*ea16f64eSAntonio Huete Jimenez * stop at a UTF-8 character boundary if we run out of space" routine.
94*ea16f64eSAntonio Huete Jimenez */
95*ea16f64eSAntonio Huete Jimenez #define IS_LEADING_SURROGATE(c) \
96*ea16f64eSAntonio Huete Jimenez ((c) >= 0xd800 && (c) < 0xdc00)
97*ea16f64eSAntonio Huete Jimenez #define IS_TRAILING_SURROGATE(c) \
98*ea16f64eSAntonio Huete Jimenez ((c) >= 0xdc00 && (c) < 0xe000)
99*ea16f64eSAntonio Huete Jimenez #define SURROGATE_VALUE(leading, trailing) \
100*ea16f64eSAntonio Huete Jimenez (((((leading) - 0xd800) << 10) | ((trailing) - 0xdc00)) + 0x10000)
101*ea16f64eSAntonio Huete Jimenez #define REPLACEMENT_CHARACTER 0x0FFFD
102*ea16f64eSAntonio Huete Jimenez
103*ea16f64eSAntonio Huete Jimenez static char *
utf_16le_to_utf_8_truncated(const wchar_t * utf_16,char * utf_8,size_t utf_8_len)104*ea16f64eSAntonio Huete Jimenez utf_16le_to_utf_8_truncated(const wchar_t *utf_16, char *utf_8,
105*ea16f64eSAntonio Huete Jimenez size_t utf_8_len)
106*ea16f64eSAntonio Huete Jimenez {
107*ea16f64eSAntonio Huete Jimenez wchar_t c, c2;
108*ea16f64eSAntonio Huete Jimenez uint32_t uc;
109*ea16f64eSAntonio Huete Jimenez
110*ea16f64eSAntonio Huete Jimenez if (utf_8_len == 0) {
111*ea16f64eSAntonio Huete Jimenez /*
112*ea16f64eSAntonio Huete Jimenez * Not even enough room for a trailing '\0'.
113*ea16f64eSAntonio Huete Jimenez * Don't put anything into the buffer.
114*ea16f64eSAntonio Huete Jimenez */
115*ea16f64eSAntonio Huete Jimenez return (utf_8);
116*ea16f64eSAntonio Huete Jimenez }
117*ea16f64eSAntonio Huete Jimenez
118*ea16f64eSAntonio Huete Jimenez while ((c = *utf_16++) != '\0') {
119*ea16f64eSAntonio Huete Jimenez if (IS_LEADING_SURROGATE(c)) {
120*ea16f64eSAntonio Huete Jimenez /*
121*ea16f64eSAntonio Huete Jimenez * Leading surrogate. Must be followed by
122*ea16f64eSAntonio Huete Jimenez * a trailing surrogate.
123*ea16f64eSAntonio Huete Jimenez */
124*ea16f64eSAntonio Huete Jimenez c2 = *utf_16;
125*ea16f64eSAntonio Huete Jimenez if (c2 == '\0') {
126*ea16f64eSAntonio Huete Jimenez /*
127*ea16f64eSAntonio Huete Jimenez * Oops, string ends with a lead
128*ea16f64eSAntonio Huete Jimenez * surrogate. Try to drop in
129*ea16f64eSAntonio Huete Jimenez * a REPLACEMENT CHARACTER, and
130*ea16f64eSAntonio Huete Jimenez * don't move the string pointer,
131*ea16f64eSAntonio Huete Jimenez * so on the next trip through
132*ea16f64eSAntonio Huete Jimenez * the loop we grab the terminating
133*ea16f64eSAntonio Huete Jimenez * '\0' and quit.
134*ea16f64eSAntonio Huete Jimenez */
135*ea16f64eSAntonio Huete Jimenez uc = REPLACEMENT_CHARACTER;
136*ea16f64eSAntonio Huete Jimenez } else {
137*ea16f64eSAntonio Huete Jimenez /*
138*ea16f64eSAntonio Huete Jimenez * OK, we can consume this 2-octet
139*ea16f64eSAntonio Huete Jimenez * value.
140*ea16f64eSAntonio Huete Jimenez */
141*ea16f64eSAntonio Huete Jimenez utf_16++;
142*ea16f64eSAntonio Huete Jimenez if (IS_TRAILING_SURROGATE(c2)) {
143*ea16f64eSAntonio Huete Jimenez /*
144*ea16f64eSAntonio Huete Jimenez * Trailing surrogate.
145*ea16f64eSAntonio Huete Jimenez * This calculation will,
146*ea16f64eSAntonio Huete Jimenez * for c being a leading
147*ea16f64eSAntonio Huete Jimenez * surrogate and c2 being
148*ea16f64eSAntonio Huete Jimenez * a trailing surrogate,
149*ea16f64eSAntonio Huete Jimenez * produce a value between
150*ea16f64eSAntonio Huete Jimenez * 0x100000 and 0x10ffff,
151*ea16f64eSAntonio Huete Jimenez * so it's always going to be
152*ea16f64eSAntonio Huete Jimenez * a valid Unicode code point.
153*ea16f64eSAntonio Huete Jimenez */
154*ea16f64eSAntonio Huete Jimenez uc = SURROGATE_VALUE(c, c2);
155*ea16f64eSAntonio Huete Jimenez } else {
156*ea16f64eSAntonio Huete Jimenez /*
157*ea16f64eSAntonio Huete Jimenez * Not a trailing surroage;
158*ea16f64eSAntonio Huete Jimenez * try to drop in a
159*ea16f64eSAntonio Huete Jimenez * REPLACEMENT CHARACTER.
160*ea16f64eSAntonio Huete Jimenez */
161*ea16f64eSAntonio Huete Jimenez uc = REPLACEMENT_CHARACTER;
162*ea16f64eSAntonio Huete Jimenez }
163*ea16f64eSAntonio Huete Jimenez }
164*ea16f64eSAntonio Huete Jimenez } else {
165*ea16f64eSAntonio Huete Jimenez /*
166*ea16f64eSAntonio Huete Jimenez * Not a leading surrogate.
167*ea16f64eSAntonio Huete Jimenez */
168*ea16f64eSAntonio Huete Jimenez if (IS_TRAILING_SURROGATE(c)) {
169*ea16f64eSAntonio Huete Jimenez /*
170*ea16f64eSAntonio Huete Jimenez * Trailing surrogate without
171*ea16f64eSAntonio Huete Jimenez * a preceding leading surrogate.
172*ea16f64eSAntonio Huete Jimenez * Try to drop in a REPLACEMENT
173*ea16f64eSAntonio Huete Jimenez * CHARACTER.
174*ea16f64eSAntonio Huete Jimenez */
175*ea16f64eSAntonio Huete Jimenez uc = REPLACEMENT_CHARACTER;
176*ea16f64eSAntonio Huete Jimenez } else {
177*ea16f64eSAntonio Huete Jimenez /*
178*ea16f64eSAntonio Huete Jimenez * This is a valid BMP character;
179*ea16f64eSAntonio Huete Jimenez * drop it in.
180*ea16f64eSAntonio Huete Jimenez */
181*ea16f64eSAntonio Huete Jimenez uc = c;
182*ea16f64eSAntonio Huete Jimenez }
183*ea16f64eSAntonio Huete Jimenez }
184*ea16f64eSAntonio Huete Jimenez
185*ea16f64eSAntonio Huete Jimenez /*
186*ea16f64eSAntonio Huete Jimenez * OK, uc is a valid Unicode character; how
187*ea16f64eSAntonio Huete Jimenez * many bytes worth of UTF-8 does it require?
188*ea16f64eSAntonio Huete Jimenez */
189*ea16f64eSAntonio Huete Jimenez if (uc < 0x0080) {
190*ea16f64eSAntonio Huete Jimenez /* 1 byte. */
191*ea16f64eSAntonio Huete Jimenez if (utf_8_len < 2) {
192*ea16f64eSAntonio Huete Jimenez /*
193*ea16f64eSAntonio Huete Jimenez * Not enough room for that byte
194*ea16f64eSAntonio Huete Jimenez * plus a trailing '\0'.
195*ea16f64eSAntonio Huete Jimenez */
196*ea16f64eSAntonio Huete Jimenez break;
197*ea16f64eSAntonio Huete Jimenez }
198*ea16f64eSAntonio Huete Jimenez *utf_8++ = (char)uc;
199*ea16f64eSAntonio Huete Jimenez utf_8_len--;
200*ea16f64eSAntonio Huete Jimenez } else if (uc < 0x0800) {
201*ea16f64eSAntonio Huete Jimenez /* 2 bytes. */
202*ea16f64eSAntonio Huete Jimenez if (utf_8_len < 3) {
203*ea16f64eSAntonio Huete Jimenez /*
204*ea16f64eSAntonio Huete Jimenez * Not enough room for those bytes
205*ea16f64eSAntonio Huete Jimenez * plus a trailing '\0'.
206*ea16f64eSAntonio Huete Jimenez */
207*ea16f64eSAntonio Huete Jimenez break;
208*ea16f64eSAntonio Huete Jimenez }
209*ea16f64eSAntonio Huete Jimenez *utf_8++ = ((uc >> 6) & 0x3F) | 0xC0;
210*ea16f64eSAntonio Huete Jimenez *utf_8++ = ((uc >> 0) & 0x3F) | 0x80;
211*ea16f64eSAntonio Huete Jimenez utf_8_len -= 2;
212*ea16f64eSAntonio Huete Jimenez } else if (uc < 0x010000) {
213*ea16f64eSAntonio Huete Jimenez /* 3 bytes. */
214*ea16f64eSAntonio Huete Jimenez if (utf_8_len < 4) {
215*ea16f64eSAntonio Huete Jimenez /*
216*ea16f64eSAntonio Huete Jimenez * Not enough room for those bytes
217*ea16f64eSAntonio Huete Jimenez * plus a trailing '\0'.
218*ea16f64eSAntonio Huete Jimenez */
219*ea16f64eSAntonio Huete Jimenez break;
220*ea16f64eSAntonio Huete Jimenez }
221*ea16f64eSAntonio Huete Jimenez *utf_8++ = ((uc >> 12) & 0x0F) | 0xE0;
222*ea16f64eSAntonio Huete Jimenez *utf_8++ = ((uc >> 6) & 0x3F) | 0x80;
223*ea16f64eSAntonio Huete Jimenez *utf_8++ = ((uc >> 0) & 0x3F) | 0x80;
224*ea16f64eSAntonio Huete Jimenez utf_8_len -= 3;
225*ea16f64eSAntonio Huete Jimenez } else {
226*ea16f64eSAntonio Huete Jimenez /* 4 bytes. */
227*ea16f64eSAntonio Huete Jimenez if (utf_8_len < 5) {
228*ea16f64eSAntonio Huete Jimenez /*
229*ea16f64eSAntonio Huete Jimenez * Not enough room for those bytes
230*ea16f64eSAntonio Huete Jimenez * plus a trailing '\0'.
231*ea16f64eSAntonio Huete Jimenez */
232*ea16f64eSAntonio Huete Jimenez break;
233*ea16f64eSAntonio Huete Jimenez }
234*ea16f64eSAntonio Huete Jimenez *utf_8++ = ((uc >> 18) & 0x03) | 0xF0;
235*ea16f64eSAntonio Huete Jimenez *utf_8++ = ((uc >> 12) & 0x3F) | 0x80;
236*ea16f64eSAntonio Huete Jimenez *utf_8++ = ((uc >> 6) & 0x3F) | 0x80;
237*ea16f64eSAntonio Huete Jimenez *utf_8++ = ((uc >> 0) & 0x3F) | 0x80;
238*ea16f64eSAntonio Huete Jimenez utf_8_len -= 3;
239*ea16f64eSAntonio Huete Jimenez }
240*ea16f64eSAntonio Huete Jimenez }
241*ea16f64eSAntonio Huete Jimenez
242*ea16f64eSAntonio Huete Jimenez /*
243*ea16f64eSAntonio Huete Jimenez * OK, we have enough room for (at least) a trailing '\0'.
244*ea16f64eSAntonio Huete Jimenez * (We started out with enough room, thanks to the test
245*ea16f64eSAntonio Huete Jimenez * for a zero-length buffer at the beginning, and if
246*ea16f64eSAntonio Huete Jimenez * there wasn't enough room for any character we wanted
247*ea16f64eSAntonio Huete Jimenez * to put into the buffer *plus* a trailing '\0',
248*ea16f64eSAntonio Huete Jimenez * we'd have quit before putting it into the buffer,
249*ea16f64eSAntonio Huete Jimenez * and thus would have left enough room for the trailing
250*ea16f64eSAntonio Huete Jimenez * '\0'.)
251*ea16f64eSAntonio Huete Jimenez *
252*ea16f64eSAntonio Huete Jimenez * Drop it in.
253*ea16f64eSAntonio Huete Jimenez */
254*ea16f64eSAntonio Huete Jimenez *utf_8 = '\0';
255*ea16f64eSAntonio Huete Jimenez
256*ea16f64eSAntonio Huete Jimenez /*
257*ea16f64eSAntonio Huete Jimenez * Return a pointer to the terminating '\0', in case we
258*ea16f64eSAntonio Huete Jimenez * want to drop something in after that.
259*ea16f64eSAntonio Huete Jimenez */
260*ea16f64eSAntonio Huete Jimenez return (utf_8);
261*ea16f64eSAntonio Huete Jimenez }
262*ea16f64eSAntonio Huete Jimenez #endif /* _WIN32 */
263*ea16f64eSAntonio Huete Jimenez
2643a289941SAaron LI /*
2653a289941SAaron LI * Generate an error message based on a format, arguments, and an
2663a289941SAaron LI * errno, with a message for the errno after the formatted output.
2673a289941SAaron LI */
2683a289941SAaron LI void
pcap_fmt_errmsg_for_errno(char * errbuf,size_t errbuflen,int errnum,const char * fmt,...)2693a289941SAaron LI pcap_fmt_errmsg_for_errno(char *errbuf, size_t errbuflen, int errnum,
2703a289941SAaron LI const char *fmt, ...)
2713a289941SAaron LI {
2723a289941SAaron LI va_list ap;
2733a289941SAaron LI size_t msglen;
2743a289941SAaron LI char *p;
2753a289941SAaron LI size_t errbuflen_remaining;
2763a289941SAaron LI
2773a289941SAaron LI va_start(ap, fmt);
278*ea16f64eSAntonio Huete Jimenez vsnprintf(errbuf, errbuflen, fmt, ap);
2793a289941SAaron LI va_end(ap);
2803a289941SAaron LI msglen = strlen(errbuf);
2813a289941SAaron LI
2823a289941SAaron LI /*
2833a289941SAaron LI * Do we have enough space to append ": "?
2843a289941SAaron LI * Including the terminating '\0', that's 3 bytes.
2853a289941SAaron LI */
2863a289941SAaron LI if (msglen + 3 > errbuflen) {
2873a289941SAaron LI /* No - just give them what we've produced. */
2883a289941SAaron LI return;
2893a289941SAaron LI }
2903a289941SAaron LI p = errbuf + msglen;
2913a289941SAaron LI errbuflen_remaining = errbuflen - msglen;
2923a289941SAaron LI *p++ = ':';
2933a289941SAaron LI *p++ = ' ';
2943a289941SAaron LI *p = '\0';
2953a289941SAaron LI errbuflen_remaining -= 2;
2963a289941SAaron LI
2973a289941SAaron LI /*
2983a289941SAaron LI * Now append the string for the error code.
2993a289941SAaron LI */
300*ea16f64eSAntonio Huete Jimenez #if defined(HAVE__WCSERROR_S)
3013a289941SAaron LI /*
302*ea16f64eSAntonio Huete Jimenez * We have a Windows-style _wcserror_s().
303*ea16f64eSAntonio Huete Jimenez * Generate a UTF-16LE error message.
3043a289941SAaron LI */
305*ea16f64eSAntonio Huete Jimenez wchar_t utf_16_errbuf[PCAP_ERRBUF_SIZE];
306*ea16f64eSAntonio Huete Jimenez errno_t err = _wcserror_s(utf_16_errbuf, PCAP_ERRBUF_SIZE, errnum);
3073a289941SAaron LI if (err != 0) {
3083a289941SAaron LI /*
3093a289941SAaron LI * It doesn't appear to be documented anywhere obvious
310*ea16f64eSAntonio Huete Jimenez * what the error returns from _wcserror_s().
3113a289941SAaron LI */
312*ea16f64eSAntonio Huete Jimenez snprintf(p, errbuflen_remaining, "Error %d", errnum);
313*ea16f64eSAntonio Huete Jimenez return;
3143a289941SAaron LI }
315*ea16f64eSAntonio Huete Jimenez
316*ea16f64eSAntonio Huete Jimenez /*
317*ea16f64eSAntonio Huete Jimenez * Now convert it from UTF-16LE to UTF-8, dropping it in the
318*ea16f64eSAntonio Huete Jimenez * remaining space in the buffer, and truncating it - cleanly,
319*ea16f64eSAntonio Huete Jimenez * on a UTF-8 character boundary - if it doesn't fit.
320*ea16f64eSAntonio Huete Jimenez */
321*ea16f64eSAntonio Huete Jimenez utf_16le_to_utf_8_truncated(utf_16_errbuf, p, errbuflen_remaining);
322*ea16f64eSAntonio Huete Jimenez
323*ea16f64eSAntonio Huete Jimenez /*
324*ea16f64eSAntonio Huete Jimenez * Now, if we're not in UTF-8 mode, convert errbuf to the
325*ea16f64eSAntonio Huete Jimenez * local code page.
326*ea16f64eSAntonio Huete Jimenez */
327*ea16f64eSAntonio Huete Jimenez if (!use_utf_8)
328*ea16f64eSAntonio Huete Jimenez utf_8_to_acp_truncated(errbuf);
3293a289941SAaron LI #elif defined(HAVE_GNU_STRERROR_R)
3303a289941SAaron LI /*
3313a289941SAaron LI * We have a GNU-style strerror_r(), which is *not* guaranteed to
3323a289941SAaron LI * do anything to the buffer handed to it, and which returns a
3333a289941SAaron LI * pointer to the error string, which may or may not be in
3343a289941SAaron LI * the buffer.
3353a289941SAaron LI *
3363a289941SAaron LI * It is, however, guaranteed to succeed.
3373a289941SAaron LI */
3383a289941SAaron LI char strerror_buf[PCAP_ERRBUF_SIZE];
3393a289941SAaron LI char *errstring = strerror_r(errnum, strerror_buf, PCAP_ERRBUF_SIZE);
340*ea16f64eSAntonio Huete Jimenez snprintf(p, errbuflen_remaining, "%s", errstring);
3413a289941SAaron LI #elif defined(HAVE_POSIX_STRERROR_R)
3423a289941SAaron LI /*
3433a289941SAaron LI * We have a POSIX-style strerror_r(), which is guaranteed to fill
3443a289941SAaron LI * in the buffer, but is not guaranteed to succeed.
3453a289941SAaron LI */
3463a289941SAaron LI int err = strerror_r(errnum, p, errbuflen_remaining);
3473a289941SAaron LI if (err == EINVAL) {
3483a289941SAaron LI /*
3493a289941SAaron LI * UNIX 03 says this isn't guaranteed to produce a
3503a289941SAaron LI * fallback error message.
3513a289941SAaron LI */
352*ea16f64eSAntonio Huete Jimenez snprintf(p, errbuflen_remaining, "Unknown error: %d",
3533a289941SAaron LI errnum);
3543a289941SAaron LI } else if (err == ERANGE) {
3553a289941SAaron LI /*
3563a289941SAaron LI * UNIX 03 says this isn't guaranteed to produce a
3573a289941SAaron LI * fallback error message.
3583a289941SAaron LI */
359*ea16f64eSAntonio Huete Jimenez snprintf(p, errbuflen_remaining,
3603a289941SAaron LI "Message for error %d is too long", errnum);
3613a289941SAaron LI }
3623a289941SAaron LI #else
3633a289941SAaron LI /*
364*ea16f64eSAntonio Huete Jimenez * We have neither _wcserror_s() nor strerror_r(), so we're
3653a289941SAaron LI * stuck with using pcap_strerror().
3663a289941SAaron LI */
367*ea16f64eSAntonio Huete Jimenez snprintf(p, errbuflen_remaining, "%s", pcap_strerror(errnum));
3683a289941SAaron LI #endif
3693a289941SAaron LI }
3703a289941SAaron LI
3713a289941SAaron LI #ifdef _WIN32
3723a289941SAaron LI /*
3733a289941SAaron LI * Generate an error message based on a format, arguments, and a
3743a289941SAaron LI * Win32 error, with a message for the Win32 error after the formatted output.
3753a289941SAaron LI */
3763a289941SAaron LI void
pcap_fmt_errmsg_for_win32_err(char * errbuf,size_t errbuflen,DWORD errnum,const char * fmt,...)3773a289941SAaron LI pcap_fmt_errmsg_for_win32_err(char *errbuf, size_t errbuflen, DWORD errnum,
3783a289941SAaron LI const char *fmt, ...)
3793a289941SAaron LI {
3803a289941SAaron LI va_list ap;
3813a289941SAaron LI size_t msglen;
3823a289941SAaron LI char *p;
3833a289941SAaron LI size_t errbuflen_remaining;
3843a289941SAaron LI DWORD retval;
385*ea16f64eSAntonio Huete Jimenez wchar_t utf_16_errbuf[PCAP_ERRBUF_SIZE];
386*ea16f64eSAntonio Huete Jimenez size_t utf_8_len;
3873a289941SAaron LI
3883a289941SAaron LI va_start(ap, fmt);
389*ea16f64eSAntonio Huete Jimenez vsnprintf(errbuf, errbuflen, fmt, ap);
3903a289941SAaron LI va_end(ap);
3913a289941SAaron LI msglen = strlen(errbuf);
3923a289941SAaron LI
3933a289941SAaron LI /*
3943a289941SAaron LI * Do we have enough space to append ": "?
3953a289941SAaron LI * Including the terminating '\0', that's 3 bytes.
3963a289941SAaron LI */
3973a289941SAaron LI if (msglen + 3 > errbuflen) {
3983a289941SAaron LI /* No - just give them what we've produced. */
3993a289941SAaron LI return;
4003a289941SAaron LI }
4013a289941SAaron LI p = errbuf + msglen;
4023a289941SAaron LI errbuflen_remaining = errbuflen - msglen;
4033a289941SAaron LI *p++ = ':';
4043a289941SAaron LI *p++ = ' ';
4053a289941SAaron LI *p = '\0';
4063a289941SAaron LI msglen += 2;
4073a289941SAaron LI errbuflen_remaining -= 2;
4083a289941SAaron LI
4093a289941SAaron LI /*
4103a289941SAaron LI * Now append the string for the error code.
4113a289941SAaron LI *
4123a289941SAaron LI * XXX - what language ID to use?
4133a289941SAaron LI *
4143a289941SAaron LI * For UN*Xes, pcap_strerror() may or may not return localized
4153a289941SAaron LI * strings.
4163a289941SAaron LI *
4173a289941SAaron LI * We currently don't have localized messages for libpcap, but
4183a289941SAaron LI * we might want to do so. On the other hand, if most of these
4193a289941SAaron LI * messages are going to be read by libpcap developers and
4203a289941SAaron LI * perhaps by developers of libpcap-based applications, English
4213a289941SAaron LI * might be a better choice, so the developer doesn't have to
4223a289941SAaron LI * get the message translated if it's in a language they don't
4233a289941SAaron LI * happen to understand.
4243a289941SAaron LI */
425*ea16f64eSAntonio Huete Jimenez retval = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS|FORMAT_MESSAGE_MAX_WIDTH_MASK,
4263a289941SAaron LI NULL, errnum, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
427*ea16f64eSAntonio Huete Jimenez utf_16_errbuf, PCAP_ERRBUF_SIZE, NULL);
4283a289941SAaron LI if (retval == 0) {
4293a289941SAaron LI /*
4303a289941SAaron LI * Failed.
4313a289941SAaron LI */
432*ea16f64eSAntonio Huete Jimenez snprintf(p, errbuflen_remaining,
4333a289941SAaron LI "Couldn't get error message for error (%lu)", errnum);
4343a289941SAaron LI return;
4353a289941SAaron LI }
4363a289941SAaron LI
437*ea16f64eSAntonio Huete Jimenez /*
438*ea16f64eSAntonio Huete Jimenez * Now convert it from UTF-16LE to UTF-8.
439*ea16f64eSAntonio Huete Jimenez */
440*ea16f64eSAntonio Huete Jimenez p = utf_16le_to_utf_8_truncated(utf_16_errbuf, p, errbuflen_remaining);
441*ea16f64eSAntonio Huete Jimenez
442*ea16f64eSAntonio Huete Jimenez /*
443*ea16f64eSAntonio Huete Jimenez * Now append the error number, if it fits.
444*ea16f64eSAntonio Huete Jimenez */
445*ea16f64eSAntonio Huete Jimenez utf_8_len = p - errbuf;
446*ea16f64eSAntonio Huete Jimenez errbuflen_remaining -= utf_8_len;
447*ea16f64eSAntonio Huete Jimenez if (utf_8_len == 0) {
448*ea16f64eSAntonio Huete Jimenez /* The message was empty. */
449*ea16f64eSAntonio Huete Jimenez snprintf(p, errbuflen_remaining, "(%lu)", errnum);
450*ea16f64eSAntonio Huete Jimenez } else
451*ea16f64eSAntonio Huete Jimenez snprintf(p, errbuflen_remaining, " (%lu)", errnum);
452*ea16f64eSAntonio Huete Jimenez
453*ea16f64eSAntonio Huete Jimenez /*
454*ea16f64eSAntonio Huete Jimenez * Now, if we're not in UTF-8 mode, convert errbuf to the
455*ea16f64eSAntonio Huete Jimenez * local code page.
456*ea16f64eSAntonio Huete Jimenez */
457*ea16f64eSAntonio Huete Jimenez if (!use_utf_8)
458*ea16f64eSAntonio Huete Jimenez utf_8_to_acp_truncated(errbuf);
4593a289941SAaron LI }
4603a289941SAaron LI #endif
461