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