diff options
Diffstat (limited to 'misc/unix/errorcodes.c')
-rw-r--r-- | misc/unix/errorcodes.c | 443 |
1 files changed, 443 insertions, 0 deletions
diff --git a/misc/unix/errorcodes.c b/misc/unix/errorcodes.c new file mode 100644 index 0000000..60ea2f7 --- /dev/null +++ b/misc/unix/errorcodes.c @@ -0,0 +1,443 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "apr_arch_misc.h" +#include "apr_strings.h" +#include "apr_lib.h" +#include "apr_dso.h" + +#if APR_HAVE_NETDB_H +#include <netdb.h> +#endif +#ifdef HAVE_DLFCN_H +#include <dlfcn.h> +#endif + +/* + * stuffbuffer - like apr_cpystrn() but returns the address of the + * dest buffer instead of the address of the terminating '\0' + */ +static char *stuffbuffer(char *buf, apr_size_t bufsize, const char *s) +{ + apr_cpystrn(buf,s,bufsize); + return buf; +} + +static char *apr_error_string(apr_status_t statcode) +{ + switch (statcode) { + case APR_ENOSTAT: + return "Could not perform a stat on the file."; + case APR_ENOPOOL: + return "A new pool could not be created."; + case APR_EBADDATE: + return "An invalid date has been provided"; + case APR_EINVALSOCK: + return "An invalid socket was returned"; + case APR_ENOPROC: + return "No process was provided and one was required."; + case APR_ENOTIME: + return "No time was provided and one was required."; + case APR_ENODIR: + return "No directory was provided and one was required."; + case APR_ENOLOCK: + return "No lock was provided and one was required."; + case APR_ENOPOLL: + return "No poll structure was provided and one was required."; + case APR_ENOSOCKET: + return "No socket was provided and one was required."; + case APR_ENOTHREAD: + return "No thread was provided and one was required."; + case APR_ENOTHDKEY: + return "No thread key structure was provided and one was required."; + case APR_ENOSHMAVAIL: + return "No shared memory is currently available"; + case APR_EDSOOPEN: +#if APR_HAS_DSO && defined(HAVE_LIBDL) + return dlerror(); +#else + return "DSO load failed"; +#endif /* HAVE_LIBDL */ + case APR_EBADIP: + return "The specified IP address is invalid."; + case APR_EBADMASK: + return "The specified network mask is invalid."; + case APR_ESYMNOTFOUND: + return "Could not find the requested symbol."; + case APR_ENOTENOUGHENTROPY: + return "Not enough entropy to continue."; + case APR_INCHILD: + return + "Your code just forked, and you are currently executing in the " + "child process"; + case APR_INPARENT: + return + "Your code just forked, and you are currently executing in the " + "parent process"; + case APR_DETACH: + return "The specified thread is detached"; + case APR_NOTDETACH: + return "The specified thread is not detached"; + case APR_CHILD_DONE: + return "The specified child process is done executing"; + case APR_CHILD_NOTDONE: + return "The specified child process is not done executing"; + case APR_TIMEUP: + return "The timeout specified has expired"; + case APR_INCOMPLETE: + return "Partial results are valid but processing is incomplete"; + case APR_BADCH: + return "Bad character specified on command line"; + case APR_BADARG: + return "Missing parameter for the specified command line option"; + case APR_EOF: + return "End of file found"; + case APR_NOTFOUND: + return "Could not find specified socket in poll list."; + case APR_ANONYMOUS: + return "Shared memory is implemented anonymously"; + case APR_FILEBASED: + return "Shared memory is implemented using files"; + case APR_KEYBASED: + return "Shared memory is implemented using a key system"; + case APR_EINIT: + return + "There is no error, this value signifies an initialized " + "error code"; + case APR_ENOTIMPL: + return "This function has not been implemented on this platform"; + case APR_EMISMATCH: + return "passwords do not match"; + case APR_EABSOLUTE: + return "The given path is absolute"; + case APR_ERELATIVE: + return "The given path is relative"; + case APR_EINCOMPLETE: + return "The given path is incomplete"; + case APR_EABOVEROOT: + return "The given path was above the root path"; + case APR_EBADPATH: + return "The given path is misformatted or contained invalid characters"; + case APR_EPATHWILD: + return "The given path contained wildcard characters"; + case APR_EBUSY: + return "The given lock was busy."; + case APR_EPROC_UNKNOWN: + return "The process is not recognized."; + case APR_EGENERAL: + return "Internal error (specific information not available)"; + default: + return "Error string not specified yet"; + } +} + + +#ifdef OS2 +#include <ctype.h> + +int apr_canonical_error(apr_status_t err); + +static char *apr_os_strerror(char* buf, apr_size_t bufsize, int err) +{ + char result[200]; + unsigned char message[HUGE_STRING_LEN]; + ULONG len; + char *pos; + int c; + + if (err >= 10000 && err < 12000) { /* socket error codes */ + return stuffbuffer(buf, bufsize, + strerror(apr_canonical_error(err+APR_OS_START_SYSERR))); + } + else if (DosGetMessage(NULL, 0, message, HUGE_STRING_LEN, err, + "OSO001.MSG", &len) == 0) { + len--; + message[len] = 0; + pos = result; + + if (len >= sizeof(result)) + len = sizeof(result) - 1; + + for (c=0; c<len; c++) { + /* skip multiple whitespace */ + while (apr_isspace(message[c]) && apr_isspace(message[c+1])) + c++; + *(pos++) = apr_isspace(message[c]) ? ' ' : message[c]; + } + + *pos = 0; + } + else { + sprintf(result, "OS/2 error %d", err); + } + + /* Stuff the string into the caller supplied buffer, then return + * a pointer to it. + */ + return stuffbuffer(buf, bufsize, result); +} + +#elif defined(WIN32) || (defined(NETWARE) && defined(USE_WINSOCK)) + +static const struct { + apr_status_t code; + const char *msg; +} gaErrorList[] = { + {WSAEINTR, "Interrupted system call"}, + {WSAEBADF, "Bad file number"}, + {WSAEACCES, "Permission denied"}, + {WSAEFAULT, "Bad address"}, + {WSAEINVAL, "Invalid argument"}, + {WSAEMFILE, "Too many open sockets"}, + {WSAEWOULDBLOCK, "Operation would block"}, + {WSAEINPROGRESS, "Operation now in progress"}, + {WSAEALREADY, "Operation already in progress"}, + {WSAENOTSOCK, "Socket operation on non-socket"}, + {WSAEDESTADDRREQ, "Destination address required"}, + {WSAEMSGSIZE, "Message too long"}, + {WSAEPROTOTYPE, "Protocol wrong type for socket"}, + {WSAENOPROTOOPT, "Bad protocol option"}, + {WSAEPROTONOSUPPORT, "Protocol not supported"}, + {WSAESOCKTNOSUPPORT, "Socket type not supported"}, + {WSAEOPNOTSUPP, "Operation not supported on socket"}, + {WSAEPFNOSUPPORT, "Protocol family not supported"}, + {WSAEAFNOSUPPORT, "Address family not supported"}, + {WSAEADDRINUSE, "Address already in use"}, + {WSAEADDRNOTAVAIL, "Can't assign requested address"}, + {WSAENETDOWN, "Network is down"}, + {WSAENETUNREACH, "Network is unreachable"}, + {WSAENETRESET, "Net connection reset"}, + {WSAECONNABORTED, "Software caused connection abort"}, + {WSAECONNRESET, "Connection reset by peer"}, + {WSAENOBUFS, "No buffer space available"}, + {WSAEISCONN, "Socket is already connected"}, + {WSAENOTCONN, "Socket is not connected"}, + {WSAESHUTDOWN, "Can't send after socket shutdown"}, + {WSAETOOMANYREFS, "Too many references, can't splice"}, + {WSAETIMEDOUT, "Connection timed out"}, + {WSAECONNREFUSED, "Connection refused"}, + {WSAELOOP, "Too many levels of symbolic links"}, + {WSAENAMETOOLONG, "File name too long"}, + {WSAEHOSTDOWN, "Host is down"}, + {WSAEHOSTUNREACH, "No route to host"}, + {WSAENOTEMPTY, "Directory not empty"}, + {WSAEPROCLIM, "Too many processes"}, + {WSAEUSERS, "Too many users"}, + {WSAEDQUOT, "Disc quota exceeded"}, + {WSAESTALE, "Stale NFS file handle"}, + {WSAEREMOTE, "Too many levels of remote in path"}, + {WSASYSNOTREADY, "Network system is unavailable"}, + {WSAVERNOTSUPPORTED, "Winsock version out of range"}, + {WSANOTINITIALISED, "WSAStartup not yet called"}, + {WSAEDISCON, "Graceful shutdown in progress"}, + {WSAHOST_NOT_FOUND, "Host not found"}, + {WSANO_DATA, "No host data of that type was found"}, + {0, NULL} +}; + + +static char *apr_os_strerror(char *buf, apr_size_t bufsize, apr_status_t errcode) +{ + apr_size_t len=0, i; + +#ifndef NETWARE +#ifndef _WIN32_WCE + len = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM + | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + errcode, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */ + buf, + (DWORD)bufsize, + NULL); +#else /* _WIN32_WCE speaks unicode */ + LPTSTR msg = (LPTSTR) buf; + len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM + | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + errcode, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */ + msg, + (DWORD) (bufsize/sizeof(TCHAR)), + NULL); + /* in-place convert to US-ASCII, substituting '?' for non ASCII */ + for(i = 0; i <= len; i++) { + if (msg[i] < 0x80 && msg[i] >= 0) { + buf[i] = (char) msg[i]; + } else { + buf[i] = '?'; + } + } +#endif +#endif + + if (!len) { + for (i = 0; gaErrorList[i].msg; ++i) { + if (gaErrorList[i].code == errcode) { + apr_cpystrn(buf, gaErrorList[i].msg, bufsize); + len = strlen(buf); + break; + } + } + } + + if (len) { + /* FormatMessage put the message in the buffer, but it may + * have embedded a newline (\r\n), and possible more than one. + * Remove the newlines replacing them with a space. This is not + * as visually perfect as moving all the remaining message over, + * but more efficient. + */ + i = len; + while (i) { + i--; + if ((buf[i] == '\r') || (buf[i] == '\n')) + buf[i] = ' '; + } + } + else { + /* Windows didn't provide us with a message. Even stuff like * WSAECONNREFUSED won't get a message. + */ + apr_snprintf(buf, bufsize, "Unrecognized Win32 error code %d", errcode); + } + + return buf; +} + +#else +/* On Unix, apr_os_strerror() handles error codes from the resolver + * (h_errno). + */ +static char *apr_os_strerror(char* buf, apr_size_t bufsize, int err) +{ +#ifdef HAVE_HSTRERROR + return stuffbuffer(buf, bufsize, hstrerror(err)); +#else /* HAVE_HSTRERROR */ + const char *msg; + + switch(err) { + case HOST_NOT_FOUND: + msg = "Unknown host"; + break; +#if defined(NO_DATA) + case NO_DATA: +#if defined(NO_ADDRESS) && (NO_DATA != NO_ADDRESS) + case NO_ADDRESS: +#endif + msg = "No address for host"; + break; +#elif defined(NO_ADDRESS) + case NO_ADDRESS: + msg = "No address for host"; + break; +#endif /* NO_DATA */ + default: + msg = "Unrecognized resolver error"; + } + return stuffbuffer(buf, bufsize, msg); +#endif /* HAVE_STRERROR */ +} +#endif + +#if defined(HAVE_STRERROR_R) && defined(STRERROR_R_RC_INT) && !defined(BEOS) +/* AIX and Tru64 style */ +static char *native_strerror(apr_status_t statcode, char *buf, + apr_size_t bufsize) +{ + if (strerror_r(statcode, buf, bufsize) < 0) { + return stuffbuffer(buf, bufsize, + "APR does not understand this error code"); + } + else { + return buf; + } +} +#elif defined(HAVE_STRERROR_R) +/* glibc style */ + +/* BeOS has the function available, but it doesn't provide + * the prototype publicly (doh!), so to avoid a build warning + * we add a suitable prototype here. + */ +#if defined(BEOS) +const char *strerror_r(apr_status_t, char *, apr_size_t); +#endif + +static char *native_strerror(apr_status_t statcode, char *buf, + apr_size_t bufsize) +{ + const char *msg; + + buf[0] = '\0'; + msg = strerror_r(statcode, buf, bufsize); + if (buf[0] == '\0') { /* libc didn't use our buffer */ + return stuffbuffer(buf, bufsize, msg); + } + else { + return buf; + } +} +#else +/* plain old strerror(); + * thread-safe on some platforms (e.g., Solaris, OS/390) + */ +static char *native_strerror(apr_status_t statcode, char *buf, + apr_size_t bufsize) +{ +#ifdef _WIN32_WCE + static char err[32]; + sprintf(err, "Native Error #%d", statcode); + return stuffbuffer(buf, bufsize, err); +#else + const char *err = strerror(statcode); + if (err) { + return stuffbuffer(buf, bufsize, err); + } else { + return stuffbuffer(buf, bufsize, + "APR does not understand this error code"); + } +#endif +} +#endif + +APR_DECLARE(char *) apr_strerror(apr_status_t statcode, char *buf, + apr_size_t bufsize) +{ + if (statcode < APR_OS_START_ERROR) { + return native_strerror(statcode, buf, bufsize); + } + else if (statcode < APR_OS_START_USERERR) { + return stuffbuffer(buf, bufsize, apr_error_string(statcode)); + } + else if (statcode < APR_OS_START_EAIERR) { + return stuffbuffer(buf, bufsize, "APR does not understand this error code"); + } + else if (statcode < APR_OS_START_SYSERR) { +#if defined(HAVE_GAI_STRERROR) + statcode -= APR_OS_START_EAIERR; +#if defined(NEGATIVE_EAI) + statcode = -statcode; +#endif + return stuffbuffer(buf, bufsize, gai_strerror(statcode)); +#else + return stuffbuffer(buf, bufsize, "APR does not understand this error code"); +#endif + } + else { + return apr_os_strerror(buf, bufsize, statcode - APR_OS_START_SYSERR); + } +} + |