1/* Licensed to the Apache Software Foundation (ASF) under one or more 2 * contributor license agreements. See the NOTICE file distributed with 3 * this work for additional information regarding copyright ownership. 4 * The ASF licenses this file to You under the Apache License, Version 2.0 5 * (the "License"); you may not use this file except in compliance with 6 * the License. You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "apr_arch_misc.h" 18#include "apr_strings.h" 19#include "apr_lib.h" 20#include "apr_dso.h" 21 22#if APR_HAVE_NETDB_H 23#include <netdb.h> 24#endif 25#ifdef HAVE_DLFCN_H 26#include <dlfcn.h> 27#endif 28 29/* 30 * stuffbuffer - like apr_cpystrn() but returns the address of the 31 * dest buffer instead of the address of the terminating '\0' 32 */ 33static char *stuffbuffer(char *buf, apr_size_t bufsize, const char *s) 34{ 35 apr_cpystrn(buf,s,bufsize); 36 return buf; 37} 38 39static char *apr_error_string(apr_status_t statcode) 40{ 41 switch (statcode) { 42 case APR_ENOPOOL: 43 return "A new pool could not be created."; 44 case APR_EBADDATE: 45 return "An invalid date has been provided"; 46 case APR_EINVALSOCK: 47 return "An invalid socket was returned"; 48 case APR_ENOPROC: 49 return "No process was provided and one was required."; 50 case APR_ENOTIME: 51 return "No time was provided and one was required."; 52 case APR_ENODIR: 53 return "No directory was provided and one was required."; 54 case APR_ENOLOCK: 55 return "No lock was provided and one was required."; 56 case APR_ENOPOLL: 57 return "No poll structure was provided and one was required."; 58 case APR_ENOSOCKET: 59 return "No socket was provided and one was required."; 60 case APR_ENOTHREAD: 61 return "No thread was provided and one was required."; 62 case APR_ENOTHDKEY: 63 return "No thread key structure was provided and one was required."; 64 case APR_ENOSHMAVAIL: 65 return "No shared memory is currently available"; 66 case APR_EDSOOPEN: 67#if APR_HAS_DSO && defined(HAVE_LIBDL) 68 return dlerror(); 69#else 70 return "DSO load failed"; 71#endif /* HAVE_LIBDL */ 72 case APR_EBADIP: 73 return "The specified IP address is invalid."; 74 case APR_EBADMASK: 75 return "The specified network mask is invalid."; 76 77 case APR_INCHILD: 78 return 79 "Your code just forked, and you are currently executing in the " 80 "child process"; 81 case APR_INPARENT: 82 return 83 "Your code just forked, and you are currently executing in the " 84 "parent process"; 85 case APR_DETACH: 86 return "The specified thread is detached"; 87 case APR_NOTDETACH: 88 return "The specified thread is not detached"; 89 case APR_CHILD_DONE: 90 return "The specified child process is done executing"; 91 case APR_CHILD_NOTDONE: 92 return "The specified child process is not done executing"; 93 case APR_TIMEUP: 94 return "The timeout specified has expired"; 95 case APR_INCOMPLETE: 96 return "Partial results are valid but processing is incomplete"; 97 case APR_BADCH: 98 return "Bad character specified on command line"; 99 case APR_BADARG: 100 return "Missing parameter for the specified command line option"; 101 case APR_EOF: 102 return "End of file found"; 103 case APR_NOTFOUND: 104 return "Could not find specified socket in poll list."; 105 case APR_ANONYMOUS: 106 return "Shared memory is implemented anonymously"; 107 case APR_FILEBASED: 108 return "Shared memory is implemented using files"; 109 case APR_KEYBASED: 110 return "Shared memory is implemented using a key system"; 111 case APR_EINIT: 112 return 113 "There is no error, this value signifies an initialized " 114 "error code"; 115 case APR_ENOTIMPL: 116 return "This function has not been implemented on this platform"; 117 case APR_EMISMATCH: 118 return "passwords do not match"; 119 case APR_EABSOLUTE: 120 return "The given path is absolute"; 121 case APR_ERELATIVE: 122 return "The given path is relative"; 123 case APR_EINCOMPLETE: 124 return "The given path is incomplete"; 125 case APR_EABOVEROOT: 126 return "The given path was above the root path"; 127 case APR_EBADPATH: 128 return "The given path is misformatted or contained invalid characters"; 129 case APR_EPATHWILD: 130 return "The given path contained wildcard characters"; 131 case APR_EPROC_UNKNOWN: 132 return "The process is not recognized."; 133 case APR_EGENERAL: 134 return "Internal error"; 135 default: 136 return "Error string not specified yet"; 137 } 138} 139 140 141#ifdef OS2 142#include <ctype.h> 143 144int apr_canonical_error(apr_status_t err); 145 146static char *apr_os_strerror(char* buf, apr_size_t bufsize, int err) 147{ 148 char result[200]; 149 unsigned char message[HUGE_STRING_LEN]; 150 ULONG len; 151 char *pos; 152 int c; 153 154 if (err >= 10000 && err < 12000) { /* socket error codes */ 155 return stuffbuffer(buf, bufsize, 156 strerror(apr_canonical_error(err+APR_OS_START_SYSERR))); 157 } 158 else if (DosGetMessage(NULL, 0, message, HUGE_STRING_LEN, err, 159 "OSO001.MSG", &len) == 0) { 160 len--; 161 message[len] = 0; 162 pos = result; 163 164 if (len >= sizeof(result)) 165 len = sizeof(result) - 1; 166 167 for (c=0; c<len; c++) { 168 /* skip multiple whitespace */ 169 while (apr_isspace(message[c]) && apr_isspace(message[c+1])) 170 c++; 171 *(pos++) = apr_isspace(message[c]) ? ' ' : message[c]; 172 } 173 174 *pos = 0; 175 } 176 else { 177 sprintf(result, "OS/2 error %d", err); 178 } 179 180 /* Stuff the string into the caller supplied buffer, then return 181 * a pointer to it. 182 */ 183 return stuffbuffer(buf, bufsize, result); 184} 185 186#elif defined(WIN32) || (defined(NETWARE) && defined(USE_WINSOCK)) 187 188static const struct { 189 apr_status_t code; 190 const char *msg; 191} gaErrorList[] = { 192 {WSAEINTR, "Interrupted system call"}, 193 {WSAEBADF, "Bad file number"}, 194 {WSAEACCES, "Permission denied"}, 195 {WSAEFAULT, "Bad address"}, 196 {WSAEINVAL, "Invalid argument"}, 197 {WSAEMFILE, "Too many open sockets"}, 198 {WSAEWOULDBLOCK, "Operation would block"}, 199 {WSAEINPROGRESS, "Operation now in progress"}, 200 {WSAEALREADY, "Operation already in progress"}, 201 {WSAENOTSOCK, "Socket operation on non-socket"}, 202 {WSAEDESTADDRREQ, "Destination address required"}, 203 {WSAEMSGSIZE, "Message too long"}, 204 {WSAEPROTOTYPE, "Protocol wrong type for socket"}, 205 {WSAENOPROTOOPT, "Bad protocol option"}, 206 {WSAEPROTONOSUPPORT, "Protocol not supported"}, 207 {WSAESOCKTNOSUPPORT, "Socket type not supported"}, 208 {WSAEOPNOTSUPP, "Operation not supported on socket"}, 209 {WSAEPFNOSUPPORT, "Protocol family not supported"}, 210 {WSAEAFNOSUPPORT, "Address family not supported"}, 211 {WSAEADDRINUSE, "Address already in use"}, 212 {WSAEADDRNOTAVAIL, "Can't assign requested address"}, 213 {WSAENETDOWN, "Network is down"}, 214 {WSAENETUNREACH, "Network is unreachable"}, 215 {WSAENETRESET, "Net connection reset"}, 216 {WSAECONNABORTED, "Software caused connection abort"}, 217 {WSAECONNRESET, "Connection reset by peer"}, 218 {WSAENOBUFS, "No buffer space available"}, 219 {WSAEISCONN, "Socket is already connected"}, 220 {WSAENOTCONN, "Socket is not connected"}, 221 {WSAESHUTDOWN, "Can't send after socket shutdown"}, 222 {WSAETOOMANYREFS, "Too many references, can't splice"}, 223 {WSAETIMEDOUT, "Connection timed out"}, 224 {WSAECONNREFUSED, "Connection refused"}, 225 {WSAELOOP, "Too many levels of symbolic links"}, 226 {WSAENAMETOOLONG, "File name too long"}, 227 {WSAEHOSTDOWN, "Host is down"}, 228 {WSAEHOSTUNREACH, "No route to host"}, 229 {WSAENOTEMPTY, "Directory not empty"}, 230 {WSAEPROCLIM, "Too many processes"}, 231 {WSAEUSERS, "Too many users"}, 232 {WSAEDQUOT, "Disc quota exceeded"}, 233 {WSAESTALE, "Stale NFS file handle"}, 234 {WSAEREMOTE, "Too many levels of remote in path"}, 235 {WSASYSNOTREADY, "Network system is unavailable"}, 236 {WSAVERNOTSUPPORTED, "Winsock version out of range"}, 237 {WSANOTINITIALISED, "WSAStartup not yet called"}, 238 {WSAEDISCON, "Graceful shutdown in progress"}, 239 {WSAHOST_NOT_FOUND, "Host not found"}, 240 {WSANO_DATA, "No host data of that type was found"}, 241 {0, NULL} 242}; 243 244 245static char *apr_os_strerror(char *buf, apr_size_t bufsize, apr_status_t errcode) 246{ 247 apr_size_t len=0, i; 248 249#ifndef NETWARE 250#ifndef _WIN32_WCE 251 len = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM 252 | FORMAT_MESSAGE_IGNORE_INSERTS, 253 NULL, 254 errcode, 255 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */ 256 buf, 257 (DWORD)bufsize, 258 NULL); 259#else /* _WIN32_WCE speaks unicode */ 260 LPTSTR msg = (LPTSTR) buf; 261 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM 262 | FORMAT_MESSAGE_IGNORE_INSERTS, 263 NULL, 264 errcode, 265 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */ 266 msg, 267 (DWORD) (bufsize/sizeof(TCHAR)), 268 NULL); 269 /* in-place convert to US-ASCII, substituting '?' for non ASCII */ 270 for(i = 0; i <= len; i++) { 271 if (msg[i] < 0x80 && msg[i] >= 0) { 272 buf[i] = (char) msg[i]; 273 } else { 274 buf[i] = '?'; 275 } 276 } 277#endif 278#endif 279 280 if (!len) { 281 for (i = 0; gaErrorList[i].msg; ++i) { 282 if (gaErrorList[i].code == errcode) { 283 apr_cpystrn(buf, gaErrorList[i].msg, bufsize); 284 len = strlen(buf); 285 break; 286 } 287 } 288 } 289 290 if (len) { 291 /* FormatMessage put the message in the buffer, but it may 292 * have embedded a newline (\r\n), and possible more than one. 293 * Remove the newlines replacing them with a space. This is not 294 * as visually perfect as moving all the remaining message over, 295 * but more efficient. 296 */ 297 i = len; 298 while (i) { 299 i--; 300 if ((buf[i] == '\r') || (buf[i] == '\n')) 301 buf[i] = ' '; 302 } 303 } 304 else { 305 /* Windows didn't provide us with a message. Even stuff like * WSAECONNREFUSED won't get a message. 306 */ 307 apr_snprintf(buf, bufsize, "Unrecognized Win32 error code %d", errcode); 308 } 309 310 return buf; 311} 312 313#else 314/* On Unix, apr_os_strerror() handles error codes from the resolver 315 * (h_errno). 316 */ 317static char *apr_os_strerror(char* buf, apr_size_t bufsize, int err) 318{ 319#ifdef HAVE_HSTRERROR 320 return stuffbuffer(buf, bufsize, hstrerror(err)); 321#else /* HAVE_HSTRERROR */ 322 const char *msg; 323 324 switch(err) { 325 case HOST_NOT_FOUND: 326 msg = "Unknown host"; 327 break; 328#if defined(NO_DATA) 329 case NO_DATA: 330#if defined(NO_ADDRESS) && (NO_DATA != NO_ADDRESS) 331 case NO_ADDRESS: 332#endif 333 msg = "No address for host"; 334 break; 335#elif defined(NO_ADDRESS) 336 case NO_ADDRESS: 337 msg = "No address for host"; 338 break; 339#endif /* NO_DATA */ 340 default: 341 msg = "Unrecognized resolver error"; 342 } 343 return stuffbuffer(buf, bufsize, msg); 344#endif /* HAVE_STRERROR */ 345} 346#endif 347 348#if defined(HAVE_STRERROR_R) && defined(STRERROR_R_RC_INT) && !defined(BEOS) 349/* AIX and Tru64 style */ 350static char *native_strerror(apr_status_t statcode, char *buf, 351 apr_size_t bufsize) 352{ 353 if (strerror_r(statcode, buf, bufsize) < 0) { 354 return stuffbuffer(buf, bufsize, 355 "APR does not understand this error code"); 356 } 357 else { 358 return buf; 359 } 360} 361#elif defined(HAVE_STRERROR_R) 362/* glibc style */ 363 364/* BeOS has the function available, but it doesn't provide 365 * the prototype publically (doh!), so to avoid a build warning 366 * we add a suitable prototype here. 367 */ 368#if defined(BEOS) 369const char *strerror_r(apr_status_t, char *, apr_size_t); 370#endif 371 372static char *native_strerror(apr_status_t statcode, char *buf, 373 apr_size_t bufsize) 374{ 375 const char *msg; 376 377 buf[0] = '\0'; 378 msg = strerror_r(statcode, buf, bufsize); 379 if (buf[0] == '\0') { /* libc didn't use our buffer */ 380 return stuffbuffer(buf, bufsize, msg); 381 } 382 else { 383 return buf; 384 } 385} 386#else 387/* plain old strerror(); 388 * thread-safe on some platforms (e.g., Solaris, OS/390) 389 */ 390static char *native_strerror(apr_status_t statcode, char *buf, 391 apr_size_t bufsize) 392{ 393#ifdef _WIN32_WCE 394 static char err[32]; 395 sprintf(err, "Native Error #%d", statcode); 396 return stuffbuffer(buf, bufsize, err); 397#else 398 const char *err = strerror(statcode); 399 if (err) { 400 return stuffbuffer(buf, bufsize, err); 401 } else { 402 return stuffbuffer(buf, bufsize, 403 "APR does not understand this error code"); 404 } 405#endif 406} 407#endif 408 409APR_DECLARE(char *) apr_strerror(apr_status_t statcode, char *buf, 410 apr_size_t bufsize) 411{ 412 if (statcode < APR_OS_START_ERROR) { 413 return native_strerror(statcode, buf, bufsize); 414 } 415 else if (statcode < APR_OS_START_USERERR) { 416 return stuffbuffer(buf, bufsize, apr_error_string(statcode)); 417 } 418 else if (statcode < APR_OS_START_EAIERR) { 419 return stuffbuffer(buf, bufsize, "APR does not understand this error code"); 420 } 421 else if (statcode < APR_OS_START_SYSERR) { 422#if defined(HAVE_GAI_STRERROR) 423 statcode -= APR_OS_START_EAIERR; 424#if defined(NEGATIVE_EAI) 425 statcode = -statcode; 426#endif 427 return stuffbuffer(buf, bufsize, gai_strerror(statcode)); 428#else 429 return stuffbuffer(buf, bufsize, "APR does not understand this error code"); 430#endif 431 } 432 else { 433 return apr_os_strerror(buf, bufsize, statcode - APR_OS_START_SYSERR); 434 } 435} 436 437