1335640Shselasky/* 2335640Shselasky * Copyright (c) 1993, 1994, 1995, 1996, 1997, 1998 3335640Shselasky * The Regents of the University of California. All rights reserved. 4335640Shselasky * 5335640Shselasky * Redistribution and use in source and binary forms, with or without 6335640Shselasky * modification, are permitted provided that the following conditions 7335640Shselasky * are met: 8335640Shselasky * 1. Redistributions of source code must retain the above copyright 9335640Shselasky * notice, this list of conditions and the following disclaimer. 10335640Shselasky * 2. Redistributions in binary form must reproduce the above copyright 11335640Shselasky * notice, this list of conditions and the following disclaimer in the 12335640Shselasky * documentation and/or other materials provided with the distribution. 13335640Shselasky * 3. All advertising materials mentioning features or use of this software 14335640Shselasky * must display the following acknowledgement: 15335640Shselasky * This product includes software developed by the Computer Systems 16335640Shselasky * Engineering Group at Lawrence Berkeley Laboratory. 17335640Shselasky * 4. Neither the name of the University nor of the Laboratory may be used 18335640Shselasky * to endorse or promote products derived from this software without 19335640Shselasky * specific prior written permission. 20335640Shselasky * 21335640Shselasky * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22335640Shselasky * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23335640Shselasky * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24335640Shselasky * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25335640Shselasky * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26335640Shselasky * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27335640Shselasky * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28335640Shselasky * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29335640Shselasky * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30335640Shselasky * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31335640Shselasky * SUCH DAMAGE. 32335640Shselasky */ 33335640Shselasky 34335640Shselasky/* 35335640Shselasky * Utilities for message formatting used both by libpcap and rpcapd. 36335640Shselasky */ 37335640Shselasky 38335640Shselasky#ifdef HAVE_CONFIG_H 39335640Shselasky#include <config.h> 40335640Shselasky#endif 41335640Shselasky 42335640Shselasky#include "ftmacros.h" 43335640Shselasky 44335640Shselasky#include <stddef.h> 45335640Shselasky#include <stdarg.h> 46335640Shselasky#include <stdio.h> 47335640Shselasky#include <string.h> 48335640Shselasky#include <errno.h> 49335640Shselasky 50335640Shselasky#include <pcap/pcap.h> 51335640Shselasky 52335640Shselasky#include "portability.h" 53335640Shselasky 54335640Shselasky#include "fmtutils.h" 55335640Shselasky 56335640Shselasky/* 57335640Shselasky * Generate an error message based on a format, arguments, and an 58335640Shselasky * errno, with a message for the errno after the formatted output. 59335640Shselasky */ 60335640Shselaskyvoid 61335640Shselaskypcap_fmt_errmsg_for_errno(char *errbuf, size_t errbuflen, int errnum, 62335640Shselasky const char *fmt, ...) 63335640Shselasky{ 64335640Shselasky va_list ap; 65335640Shselasky size_t msglen; 66335640Shselasky char *p; 67335640Shselasky size_t errbuflen_remaining; 68335640Shselasky 69335640Shselasky va_start(ap, fmt); 70335640Shselasky pcap_vsnprintf(errbuf, errbuflen, fmt, ap); 71335640Shselasky va_end(ap); 72335640Shselasky msglen = strlen(errbuf); 73335640Shselasky 74335640Shselasky /* 75335640Shselasky * Do we have enough space to append ": "? 76335640Shselasky * Including the terminating '\0', that's 3 bytes. 77335640Shselasky */ 78335640Shselasky if (msglen + 3 > errbuflen) { 79335640Shselasky /* No - just give them what we've produced. */ 80335640Shselasky return; 81335640Shselasky } 82335640Shselasky p = errbuf + msglen; 83335640Shselasky errbuflen_remaining = errbuflen - msglen; 84335640Shselasky *p++ = ':'; 85335640Shselasky *p++ = ' '; 86335640Shselasky *p = '\0'; 87335640Shselasky msglen += 2; 88335640Shselasky errbuflen_remaining -= 2; 89335640Shselasky 90335640Shselasky /* 91335640Shselasky * Now append the string for the error code. 92335640Shselasky */ 93335640Shselasky#if defined(HAVE_STRERROR_S) 94356341Scy /* 95356341Scy * We have a Windows-style strerror_s(). 96356341Scy */ 97356341Scy errno_t err = strerror_s(p, errbuflen_remaining, errnum); 98335640Shselasky if (err != 0) { 99335640Shselasky /* 100335640Shselasky * It doesn't appear to be documented anywhere obvious 101335640Shselasky * what the error returns from strerror_s(). 102335640Shselasky */ 103335640Shselasky pcap_snprintf(p, errbuflen_remaining, "Error %d", errnum); 104335640Shselasky } 105356341Scy#elif defined(HAVE_GNU_STRERROR_R) 106356341Scy /* 107356341Scy * We have a GNU-style strerror_r(), which is *not* guaranteed to 108356341Scy * do anything to the buffer handed to it, and which returns a 109356341Scy * pointer to the error string, which may or may not be in 110356341Scy * the buffer. 111356341Scy * 112356341Scy * It is, however, guaranteed to succeed. 113356341Scy */ 114356341Scy char strerror_buf[PCAP_ERRBUF_SIZE]; 115356341Scy char *errstring = strerror_r(errnum, strerror_buf, PCAP_ERRBUF_SIZE); 116356341Scy pcap_snprintf(p, errbuflen_remaining, "%s", errstring); 117356341Scy#elif defined(HAVE_POSIX_STRERROR_R) 118356341Scy /* 119356341Scy * We have a POSIX-style strerror_r(), which is guaranteed to fill 120356341Scy * in the buffer, but is not guaranteed to succeed. 121356341Scy */ 122356341Scy int err = strerror_r(errnum, p, errbuflen_remaining); 123335640Shselasky if (err == EINVAL) { 124335640Shselasky /* 125335640Shselasky * UNIX 03 says this isn't guaranteed to produce a 126335640Shselasky * fallback error message. 127335640Shselasky */ 128335640Shselasky pcap_snprintf(p, errbuflen_remaining, "Unknown error: %d", 129335640Shselasky errnum); 130335640Shselasky } else if (err == ERANGE) { 131335640Shselasky /* 132335640Shselasky * UNIX 03 says this isn't guaranteed to produce a 133335640Shselasky * fallback error message. 134335640Shselasky */ 135335640Shselasky pcap_snprintf(p, errbuflen_remaining, 136335640Shselasky "Message for error %d is too long", errnum); 137335640Shselasky } 138335640Shselasky#else 139335640Shselasky /* 140335640Shselasky * We have neither strerror_s() nor strerror_r(), so we're 141335640Shselasky * stuck with using pcap_strerror(). 142335640Shselasky */ 143335640Shselasky pcap_snprintf(p, errbuflen_remaining, "%s", pcap_strerror(errnum)); 144335640Shselasky#endif 145335640Shselasky} 146356341Scy 147356341Scy#ifdef _WIN32 148356341Scy/* 149356341Scy * Generate an error message based on a format, arguments, and a 150356341Scy * Win32 error, with a message for the Win32 error after the formatted output. 151356341Scy */ 152356341Scyvoid 153356341Scypcap_fmt_errmsg_for_win32_err(char *errbuf, size_t errbuflen, DWORD errnum, 154356341Scy const char *fmt, ...) 155356341Scy{ 156356341Scy va_list ap; 157356341Scy size_t msglen; 158356341Scy char *p; 159356341Scy size_t errbuflen_remaining; 160356341Scy DWORD retval; 161356341Scy char win32_errbuf[PCAP_ERRBUF_SIZE+1]; 162356341Scy 163356341Scy va_start(ap, fmt); 164356341Scy pcap_vsnprintf(errbuf, errbuflen, fmt, ap); 165356341Scy va_end(ap); 166356341Scy msglen = strlen(errbuf); 167356341Scy 168356341Scy /* 169356341Scy * Do we have enough space to append ": "? 170356341Scy * Including the terminating '\0', that's 3 bytes. 171356341Scy */ 172356341Scy if (msglen + 3 > errbuflen) { 173356341Scy /* No - just give them what we've produced. */ 174356341Scy return; 175356341Scy } 176356341Scy p = errbuf + msglen; 177356341Scy errbuflen_remaining = errbuflen - msglen; 178356341Scy *p++ = ':'; 179356341Scy *p++ = ' '; 180356341Scy *p = '\0'; 181356341Scy msglen += 2; 182356341Scy errbuflen_remaining -= 2; 183356341Scy 184356341Scy /* 185356341Scy * Now append the string for the error code. 186356341Scy * 187356341Scy * XXX - what language ID to use? 188356341Scy * 189356341Scy * For UN*Xes, pcap_strerror() may or may not return localized 190356341Scy * strings. 191356341Scy * 192356341Scy * We currently don't have localized messages for libpcap, but 193356341Scy * we might want to do so. On the other hand, if most of these 194356341Scy * messages are going to be read by libpcap developers and 195356341Scy * perhaps by developers of libpcap-based applications, English 196356341Scy * might be a better choice, so the developer doesn't have to 197356341Scy * get the message translated if it's in a language they don't 198356341Scy * happen to understand. 199356341Scy */ 200356341Scy retval = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS|FORMAT_MESSAGE_MAX_WIDTH_MASK, 201356341Scy NULL, errnum, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 202356341Scy win32_errbuf, PCAP_ERRBUF_SIZE, NULL); 203356341Scy if (retval == 0) { 204356341Scy /* 205356341Scy * Failed. 206356341Scy */ 207356341Scy pcap_snprintf(p, errbuflen_remaining, 208356341Scy "Couldn't get error message for error (%lu)", errnum); 209356341Scy return; 210356341Scy } 211356341Scy 212356341Scy pcap_snprintf(p, errbuflen_remaining, "%s (%lu)", win32_errbuf, errnum); 213356341Scy} 214356341Scy#endif 215