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