1251875Speter/* Licensed to the Apache Software Foundation (ASF) under one or more 2251875Speter * contributor license agreements. See the NOTICE file distributed with 3251875Speter * this work for additional information regarding copyright ownership. 4251875Speter * The ASF licenses this file to You under the Apache License, Version 2.0 5251875Speter * (the "License"); you may not use this file except in compliance with 6251875Speter * the License. You may obtain a copy of the License at 7251875Speter * 8251875Speter * http://www.apache.org/licenses/LICENSE-2.0 9251875Speter * 10251875Speter * Unless required by applicable law or agreed to in writing, software 11251875Speter * distributed under the License is distributed on an "AS IS" BASIS, 12251875Speter * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13251875Speter * See the License for the specific language governing permissions and 14251875Speter * limitations under the License. 15251875Speter */ 16251875Speter 17251875Speter#include "apr_arch_misc.h" 18251875Speter#include "apr_strings.h" 19251875Speter#include "apr_lib.h" 20251875Speter#include "apr_dso.h" 21251875Speter 22251875Speter#if APR_HAVE_NETDB_H 23251875Speter#include <netdb.h> 24251875Speter#endif 25251875Speter#ifdef HAVE_DLFCN_H 26251875Speter#include <dlfcn.h> 27251875Speter#endif 28251875Speter 29251875Speter/* 30251875Speter * stuffbuffer - like apr_cpystrn() but returns the address of the 31251875Speter * dest buffer instead of the address of the terminating '\0' 32251875Speter */ 33251875Speterstatic char *stuffbuffer(char *buf, apr_size_t bufsize, const char *s) 34251875Speter{ 35251875Speter apr_cpystrn(buf,s,bufsize); 36251875Speter return buf; 37251875Speter} 38251875Speter 39251875Speterstatic char *apr_error_string(apr_status_t statcode) 40251875Speter{ 41251875Speter switch (statcode) { 42251875Speter case APR_ENOPOOL: 43251875Speter return "A new pool could not be created."; 44251875Speter case APR_EBADDATE: 45251875Speter return "An invalid date has been provided"; 46251875Speter case APR_EINVALSOCK: 47251875Speter return "An invalid socket was returned"; 48251875Speter case APR_ENOPROC: 49251875Speter return "No process was provided and one was required."; 50251875Speter case APR_ENOTIME: 51251875Speter return "No time was provided and one was required."; 52251875Speter case APR_ENODIR: 53251875Speter return "No directory was provided and one was required."; 54251875Speter case APR_ENOLOCK: 55251875Speter return "No lock was provided and one was required."; 56251875Speter case APR_ENOPOLL: 57251875Speter return "No poll structure was provided and one was required."; 58251875Speter case APR_ENOSOCKET: 59251875Speter return "No socket was provided and one was required."; 60251875Speter case APR_ENOTHREAD: 61251875Speter return "No thread was provided and one was required."; 62251875Speter case APR_ENOTHDKEY: 63251875Speter return "No thread key structure was provided and one was required."; 64251875Speter case APR_ENOSHMAVAIL: 65251875Speter return "No shared memory is currently available"; 66251875Speter case APR_EDSOOPEN: 67251875Speter#if APR_HAS_DSO && defined(HAVE_LIBDL) 68251875Speter return dlerror(); 69251875Speter#else 70251875Speter return "DSO load failed"; 71251875Speter#endif /* HAVE_LIBDL */ 72251875Speter case APR_EBADIP: 73251875Speter return "The specified IP address is invalid."; 74251875Speter case APR_EBADMASK: 75251875Speter return "The specified network mask is invalid."; 76251875Speter 77251875Speter case APR_INCHILD: 78251875Speter return 79251875Speter "Your code just forked, and you are currently executing in the " 80251875Speter "child process"; 81251875Speter case APR_INPARENT: 82251875Speter return 83251875Speter "Your code just forked, and you are currently executing in the " 84251875Speter "parent process"; 85251875Speter case APR_DETACH: 86251875Speter return "The specified thread is detached"; 87251875Speter case APR_NOTDETACH: 88251875Speter return "The specified thread is not detached"; 89251875Speter case APR_CHILD_DONE: 90251875Speter return "The specified child process is done executing"; 91251875Speter case APR_CHILD_NOTDONE: 92251875Speter return "The specified child process is not done executing"; 93251875Speter case APR_TIMEUP: 94251875Speter return "The timeout specified has expired"; 95251875Speter case APR_INCOMPLETE: 96251875Speter return "Partial results are valid but processing is incomplete"; 97251875Speter case APR_BADCH: 98251875Speter return "Bad character specified on command line"; 99251875Speter case APR_BADARG: 100251875Speter return "Missing parameter for the specified command line option"; 101251875Speter case APR_EOF: 102251875Speter return "End of file found"; 103251875Speter case APR_NOTFOUND: 104251875Speter return "Could not find specified socket in poll list."; 105251875Speter case APR_ANONYMOUS: 106251875Speter return "Shared memory is implemented anonymously"; 107251875Speter case APR_FILEBASED: 108251875Speter return "Shared memory is implemented using files"; 109251875Speter case APR_KEYBASED: 110251875Speter return "Shared memory is implemented using a key system"; 111251875Speter case APR_EINIT: 112251875Speter return 113251875Speter "There is no error, this value signifies an initialized " 114251875Speter "error code"; 115251875Speter case APR_ENOTIMPL: 116251875Speter return "This function has not been implemented on this platform"; 117251875Speter case APR_EMISMATCH: 118251875Speter return "passwords do not match"; 119251875Speter case APR_EABSOLUTE: 120251875Speter return "The given path is absolute"; 121251875Speter case APR_ERELATIVE: 122251875Speter return "The given path is relative"; 123251875Speter case APR_EINCOMPLETE: 124251875Speter return "The given path is incomplete"; 125251875Speter case APR_EABOVEROOT: 126251875Speter return "The given path was above the root path"; 127251875Speter case APR_EBADPATH: 128251875Speter return "The given path is misformatted or contained invalid characters"; 129251875Speter case APR_EPATHWILD: 130251875Speter return "The given path contained wildcard characters"; 131251875Speter case APR_EPROC_UNKNOWN: 132251875Speter return "The process is not recognized."; 133251875Speter case APR_EGENERAL: 134251875Speter return "Internal error"; 135251875Speter default: 136251875Speter return "Error string not specified yet"; 137251875Speter } 138251875Speter} 139251875Speter 140251875Speter 141251875Speter#ifdef OS2 142251875Speter#include <ctype.h> 143251875Speter 144251875Speterint apr_canonical_error(apr_status_t err); 145251875Speter 146251875Speterstatic char *apr_os_strerror(char* buf, apr_size_t bufsize, int err) 147251875Speter{ 148251875Speter char result[200]; 149251875Speter unsigned char message[HUGE_STRING_LEN]; 150251875Speter ULONG len; 151251875Speter char *pos; 152251875Speter int c; 153251875Speter 154251875Speter if (err >= 10000 && err < 12000) { /* socket error codes */ 155251875Speter return stuffbuffer(buf, bufsize, 156251875Speter strerror(apr_canonical_error(err+APR_OS_START_SYSERR))); 157251875Speter } 158251875Speter else if (DosGetMessage(NULL, 0, message, HUGE_STRING_LEN, err, 159251875Speter "OSO001.MSG", &len) == 0) { 160251875Speter len--; 161251875Speter message[len] = 0; 162251875Speter pos = result; 163251875Speter 164251875Speter if (len >= sizeof(result)) 165251875Speter len = sizeof(result) - 1; 166251875Speter 167251875Speter for (c=0; c<len; c++) { 168251875Speter /* skip multiple whitespace */ 169251875Speter while (apr_isspace(message[c]) && apr_isspace(message[c+1])) 170251875Speter c++; 171251875Speter *(pos++) = apr_isspace(message[c]) ? ' ' : message[c]; 172251875Speter } 173251875Speter 174251875Speter *pos = 0; 175251875Speter } 176251875Speter else { 177251875Speter sprintf(result, "OS/2 error %d", err); 178251875Speter } 179251875Speter 180251875Speter /* Stuff the string into the caller supplied buffer, then return 181251875Speter * a pointer to it. 182251875Speter */ 183251875Speter return stuffbuffer(buf, bufsize, result); 184251875Speter} 185251875Speter 186251875Speter#elif defined(WIN32) || (defined(NETWARE) && defined(USE_WINSOCK)) 187251875Speter 188251875Speterstatic const struct { 189251875Speter apr_status_t code; 190251875Speter const char *msg; 191251875Speter} gaErrorList[] = { 192251875Speter {WSAEINTR, "Interrupted system call"}, 193251875Speter {WSAEBADF, "Bad file number"}, 194251875Speter {WSAEACCES, "Permission denied"}, 195251875Speter {WSAEFAULT, "Bad address"}, 196251875Speter {WSAEINVAL, "Invalid argument"}, 197251875Speter {WSAEMFILE, "Too many open sockets"}, 198251875Speter {WSAEWOULDBLOCK, "Operation would block"}, 199251875Speter {WSAEINPROGRESS, "Operation now in progress"}, 200251875Speter {WSAEALREADY, "Operation already in progress"}, 201251875Speter {WSAENOTSOCK, "Socket operation on non-socket"}, 202251875Speter {WSAEDESTADDRREQ, "Destination address required"}, 203251875Speter {WSAEMSGSIZE, "Message too long"}, 204251875Speter {WSAEPROTOTYPE, "Protocol wrong type for socket"}, 205251875Speter {WSAENOPROTOOPT, "Bad protocol option"}, 206251875Speter {WSAEPROTONOSUPPORT, "Protocol not supported"}, 207251875Speter {WSAESOCKTNOSUPPORT, "Socket type not supported"}, 208251875Speter {WSAEOPNOTSUPP, "Operation not supported on socket"}, 209251875Speter {WSAEPFNOSUPPORT, "Protocol family not supported"}, 210251875Speter {WSAEAFNOSUPPORT, "Address family not supported"}, 211251875Speter {WSAEADDRINUSE, "Address already in use"}, 212251875Speter {WSAEADDRNOTAVAIL, "Can't assign requested address"}, 213251875Speter {WSAENETDOWN, "Network is down"}, 214251875Speter {WSAENETUNREACH, "Network is unreachable"}, 215251875Speter {WSAENETRESET, "Net connection reset"}, 216251875Speter {WSAECONNABORTED, "Software caused connection abort"}, 217251875Speter {WSAECONNRESET, "Connection reset by peer"}, 218251875Speter {WSAENOBUFS, "No buffer space available"}, 219251875Speter {WSAEISCONN, "Socket is already connected"}, 220251875Speter {WSAENOTCONN, "Socket is not connected"}, 221251875Speter {WSAESHUTDOWN, "Can't send after socket shutdown"}, 222251875Speter {WSAETOOMANYREFS, "Too many references, can't splice"}, 223251875Speter {WSAETIMEDOUT, "Connection timed out"}, 224251875Speter {WSAECONNREFUSED, "Connection refused"}, 225251875Speter {WSAELOOP, "Too many levels of symbolic links"}, 226251875Speter {WSAENAMETOOLONG, "File name too long"}, 227251875Speter {WSAEHOSTDOWN, "Host is down"}, 228251875Speter {WSAEHOSTUNREACH, "No route to host"}, 229251875Speter {WSAENOTEMPTY, "Directory not empty"}, 230251875Speter {WSAEPROCLIM, "Too many processes"}, 231251875Speter {WSAEUSERS, "Too many users"}, 232251875Speter {WSAEDQUOT, "Disc quota exceeded"}, 233251875Speter {WSAESTALE, "Stale NFS file handle"}, 234251875Speter {WSAEREMOTE, "Too many levels of remote in path"}, 235251875Speter {WSASYSNOTREADY, "Network system is unavailable"}, 236251875Speter {WSAVERNOTSUPPORTED, "Winsock version out of range"}, 237251875Speter {WSANOTINITIALISED, "WSAStartup not yet called"}, 238251875Speter {WSAEDISCON, "Graceful shutdown in progress"}, 239251875Speter {WSAHOST_NOT_FOUND, "Host not found"}, 240251875Speter {WSANO_DATA, "No host data of that type was found"}, 241251875Speter {0, NULL} 242251875Speter}; 243251875Speter 244251875Speter 245251875Speterstatic char *apr_os_strerror(char *buf, apr_size_t bufsize, apr_status_t errcode) 246251875Speter{ 247251875Speter apr_size_t len=0, i; 248251875Speter 249251875Speter#ifndef NETWARE 250251875Speter#ifndef _WIN32_WCE 251251875Speter len = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM 252251875Speter | FORMAT_MESSAGE_IGNORE_INSERTS, 253251875Speter NULL, 254251875Speter errcode, 255251875Speter MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */ 256251875Speter buf, 257251875Speter (DWORD)bufsize, 258251875Speter NULL); 259251875Speter#else /* _WIN32_WCE speaks unicode */ 260251875Speter LPTSTR msg = (LPTSTR) buf; 261251875Speter len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM 262251875Speter | FORMAT_MESSAGE_IGNORE_INSERTS, 263251875Speter NULL, 264251875Speter errcode, 265251875Speter MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */ 266251875Speter msg, 267251875Speter (DWORD) (bufsize/sizeof(TCHAR)), 268251875Speter NULL); 269251875Speter /* in-place convert to US-ASCII, substituting '?' for non ASCII */ 270251875Speter for(i = 0; i <= len; i++) { 271251875Speter if (msg[i] < 0x80 && msg[i] >= 0) { 272251875Speter buf[i] = (char) msg[i]; 273251875Speter } else { 274251875Speter buf[i] = '?'; 275251875Speter } 276251875Speter } 277251875Speter#endif 278251875Speter#endif 279251875Speter 280251875Speter if (!len) { 281251875Speter for (i = 0; gaErrorList[i].msg; ++i) { 282251875Speter if (gaErrorList[i].code == errcode) { 283251875Speter apr_cpystrn(buf, gaErrorList[i].msg, bufsize); 284251875Speter len = strlen(buf); 285251875Speter break; 286251875Speter } 287251875Speter } 288251875Speter } 289251875Speter 290251875Speter if (len) { 291251875Speter /* FormatMessage put the message in the buffer, but it may 292251875Speter * have embedded a newline (\r\n), and possible more than one. 293251875Speter * Remove the newlines replacing them with a space. This is not 294251875Speter * as visually perfect as moving all the remaining message over, 295251875Speter * but more efficient. 296251875Speter */ 297251875Speter i = len; 298251875Speter while (i) { 299251875Speter i--; 300251875Speter if ((buf[i] == '\r') || (buf[i] == '\n')) 301251875Speter buf[i] = ' '; 302251875Speter } 303251875Speter } 304251875Speter else { 305251875Speter /* Windows didn't provide us with a message. Even stuff like * WSAECONNREFUSED won't get a message. 306251875Speter */ 307251875Speter apr_snprintf(buf, bufsize, "Unrecognized Win32 error code %d", errcode); 308251875Speter } 309251875Speter 310251875Speter return buf; 311251875Speter} 312251875Speter 313251875Speter#else 314251875Speter/* On Unix, apr_os_strerror() handles error codes from the resolver 315251875Speter * (h_errno). 316251875Speter */ 317251875Speterstatic char *apr_os_strerror(char* buf, apr_size_t bufsize, int err) 318251875Speter{ 319251875Speter#ifdef HAVE_HSTRERROR 320251875Speter return stuffbuffer(buf, bufsize, hstrerror(err)); 321251875Speter#else /* HAVE_HSTRERROR */ 322251875Speter const char *msg; 323251875Speter 324251875Speter switch(err) { 325251875Speter case HOST_NOT_FOUND: 326251875Speter msg = "Unknown host"; 327251875Speter break; 328251875Speter#if defined(NO_DATA) 329251875Speter case NO_DATA: 330251875Speter#if defined(NO_ADDRESS) && (NO_DATA != NO_ADDRESS) 331251875Speter case NO_ADDRESS: 332251875Speter#endif 333251875Speter msg = "No address for host"; 334251875Speter break; 335251875Speter#elif defined(NO_ADDRESS) 336251875Speter case NO_ADDRESS: 337251875Speter msg = "No address for host"; 338251875Speter break; 339251875Speter#endif /* NO_DATA */ 340251875Speter default: 341251875Speter msg = "Unrecognized resolver error"; 342251875Speter } 343251875Speter return stuffbuffer(buf, bufsize, msg); 344251875Speter#endif /* HAVE_STRERROR */ 345251875Speter} 346251875Speter#endif 347251875Speter 348251875Speter#if defined(HAVE_STRERROR_R) && defined(STRERROR_R_RC_INT) && !defined(BEOS) 349251875Speter/* AIX and Tru64 style */ 350251875Speterstatic char *native_strerror(apr_status_t statcode, char *buf, 351251875Speter apr_size_t bufsize) 352251875Speter{ 353251875Speter if (strerror_r(statcode, buf, bufsize) < 0) { 354251875Speter return stuffbuffer(buf, bufsize, 355251875Speter "APR does not understand this error code"); 356251875Speter } 357251875Speter else { 358251875Speter return buf; 359251875Speter } 360251875Speter} 361251875Speter#elif defined(HAVE_STRERROR_R) 362251875Speter/* glibc style */ 363251875Speter 364251875Speter/* BeOS has the function available, but it doesn't provide 365251875Speter * the prototype publically (doh!), so to avoid a build warning 366251875Speter * we add a suitable prototype here. 367251875Speter */ 368251875Speter#if defined(BEOS) 369251875Speterconst char *strerror_r(apr_status_t, char *, apr_size_t); 370251875Speter#endif 371251875Speter 372251875Speterstatic char *native_strerror(apr_status_t statcode, char *buf, 373251875Speter apr_size_t bufsize) 374251875Speter{ 375251875Speter const char *msg; 376251875Speter 377251875Speter buf[0] = '\0'; 378251875Speter msg = strerror_r(statcode, buf, bufsize); 379251875Speter if (buf[0] == '\0') { /* libc didn't use our buffer */ 380251875Speter return stuffbuffer(buf, bufsize, msg); 381251875Speter } 382251875Speter else { 383251875Speter return buf; 384251875Speter } 385251875Speter} 386251875Speter#else 387251875Speter/* plain old strerror(); 388251875Speter * thread-safe on some platforms (e.g., Solaris, OS/390) 389251875Speter */ 390251875Speterstatic char *native_strerror(apr_status_t statcode, char *buf, 391251875Speter apr_size_t bufsize) 392251875Speter{ 393251875Speter#ifdef _WIN32_WCE 394251875Speter static char err[32]; 395251875Speter sprintf(err, "Native Error #%d", statcode); 396251875Speter return stuffbuffer(buf, bufsize, err); 397251875Speter#else 398251875Speter const char *err = strerror(statcode); 399251875Speter if (err) { 400251875Speter return stuffbuffer(buf, bufsize, err); 401251875Speter } else { 402251875Speter return stuffbuffer(buf, bufsize, 403251875Speter "APR does not understand this error code"); 404251875Speter } 405251875Speter#endif 406251875Speter} 407251875Speter#endif 408251875Speter 409251875SpeterAPR_DECLARE(char *) apr_strerror(apr_status_t statcode, char *buf, 410251875Speter apr_size_t bufsize) 411251875Speter{ 412251875Speter if (statcode < APR_OS_START_ERROR) { 413251875Speter return native_strerror(statcode, buf, bufsize); 414251875Speter } 415251875Speter else if (statcode < APR_OS_START_USERERR) { 416251875Speter return stuffbuffer(buf, bufsize, apr_error_string(statcode)); 417251875Speter } 418251875Speter else if (statcode < APR_OS_START_EAIERR) { 419251875Speter return stuffbuffer(buf, bufsize, "APR does not understand this error code"); 420251875Speter } 421251875Speter else if (statcode < APR_OS_START_SYSERR) { 422251875Speter#if defined(HAVE_GAI_STRERROR) 423251875Speter statcode -= APR_OS_START_EAIERR; 424251875Speter#if defined(NEGATIVE_EAI) 425251875Speter statcode = -statcode; 426251875Speter#endif 427251875Speter return stuffbuffer(buf, bufsize, gai_strerror(statcode)); 428251875Speter#else 429251875Speter return stuffbuffer(buf, bufsize, "APR does not understand this error code"); 430251875Speter#endif 431251875Speter } 432251875Speter else { 433251875Speter return apr_os_strerror(buf, bufsize, statcode - APR_OS_START_SYSERR); 434251875Speter } 435251875Speter} 436251875Speter 437