errorcodes.c revision 251875
1107120Sjulian/* Licensed to the Apache Software Foundation (ASF) under one or more 2107120Sjulian * contributor license agreements. See the NOTICE file distributed with 3107120Sjulian * this work for additional information regarding copyright ownership. 4107120Sjulian * The ASF licenses this file to You under the Apache License, Version 2.0 5107120Sjulian * (the "License"); you may not use this file except in compliance with 6107120Sjulian * the License. You may obtain a copy of the License at 7107120Sjulian * 8107120Sjulian * http://www.apache.org/licenses/LICENSE-2.0 9107120Sjulian * 10107120Sjulian * Unless required by applicable law or agreed to in writing, software 11107120Sjulian * distributed under the License is distributed on an "AS IS" BASIS, 12107120Sjulian * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13107120Sjulian * See the License for the specific language governing permissions and 14107120Sjulian * limitations under the License. 15107120Sjulian */ 16107120Sjulian 17107120Sjulian#include "apr_arch_misc.h" 18107120Sjulian#include "apr_strings.h" 19107120Sjulian#include "apr_lib.h" 20107120Sjulian#include "apr_dso.h" 21107120Sjulian 22107120Sjulian#if APR_HAVE_NETDB_H 23107120Sjulian#include <netdb.h> 24107120Sjulian#endif 25107120Sjulian#ifdef HAVE_DLFCN_H 26107120Sjulian#include <dlfcn.h> 27107120Sjulian#endif 28121054Semax 29107120Sjulian/* 30107120Sjulian * stuffbuffer - like apr_cpystrn() but returns the address of the 31107120Sjulian * dest buffer instead of the address of the terminating '\0' 32107120Sjulian */ 33121054Semaxstatic char *stuffbuffer(char *buf, apr_size_t bufsize, const char *s) 34107120Sjulian{ 35107120Sjulian apr_cpystrn(buf,s,bufsize); 36107120Sjulian return buf; 37107120Sjulian} 38107120Sjulian 39107120Sjulianstatic char *apr_error_string(apr_status_t statcode) 40107120Sjulian{ 41107120Sjulian switch (statcode) { 42107120Sjulian case APR_ENOPOOL: 43107120Sjulian return "A new pool could not be created."; 44107120Sjulian case APR_EBADDATE: 45107120Sjulian return "An invalid date has been provided"; 46107120Sjulian case APR_EINVALSOCK: 47107120Sjulian return "An invalid socket was returned"; 48107120Sjulian case APR_ENOPROC: 49107120Sjulian return "No process was provided and one was required."; 50121054Semax case APR_ENOTIME: 51121054Semax return "No time was provided and one was required."; 52121054Semax case APR_ENODIR: 53107120Sjulian return "No directory was provided and one was required."; 54107120Sjulian case APR_ENOLOCK: 55107120Sjulian return "No lock was provided and one was required."; 56107120Sjulian case APR_ENOPOLL: 57107120Sjulian return "No poll structure was provided and one was required."; 58107120Sjulian case APR_ENOSOCKET: 59107120Sjulian return "No socket was provided and one was required."; 60107120Sjulian case APR_ENOTHREAD: 61107120Sjulian return "No thread was provided and one was required."; 62121054Semax case APR_ENOTHDKEY: 63107120Sjulian return "No thread key structure was provided and one was required."; 64121054Semax case APR_ENOSHMAVAIL: 65121054Semax return "No shared memory is currently available"; 66121054Semax case APR_EDSOOPEN: 67107120Sjulian#if APR_HAS_DSO && defined(HAVE_LIBDL) 68121054Semax return dlerror(); 69121054Semax#else 70121054Semax return "DSO load failed"; 71121054Semax#endif /* HAVE_LIBDL */ 72107120Sjulian case APR_EBADIP: 73121054Semax return "The specified IP address is invalid."; 74107120Sjulian case APR_EBADMASK: 75121054Semax return "The specified network mask is invalid."; 76121054Semax 77121054Semax case APR_INCHILD: 78107120Sjulian return 79114879Sjulian "Your code just forked, and you are currently executing in the " 80107120Sjulian "child process"; 81107120Sjulian case APR_INPARENT: 82107120Sjulian return 83107120Sjulian "Your code just forked, and you are currently executing in the " 84107120Sjulian "parent process"; 85107120Sjulian case APR_DETACH: 86107120Sjulian return "The specified thread is detached"; 87107120Sjulian case APR_NOTDETACH: 88107120Sjulian return "The specified thread is not detached"; 89107120Sjulian case APR_CHILD_DONE: 90107120Sjulian return "The specified child process is done executing"; 91107120Sjulian case APR_CHILD_NOTDONE: 92107120Sjulian return "The specified child process is not done executing"; 93107120Sjulian case APR_TIMEUP: 94107120Sjulian return "The timeout specified has expired"; 95107120Sjulian case APR_INCOMPLETE: 96107120Sjulian return "Partial results are valid but processing is incomplete"; 97107120Sjulian case APR_BADCH: 98107120Sjulian return "Bad character specified on command line"; 99107120Sjulian case APR_BADARG: 100107120Sjulian return "Missing parameter for the specified command line option"; 101107120Sjulian case APR_EOF: 102107120Sjulian return "End of file found"; 103107120Sjulian case APR_NOTFOUND: 104107120Sjulian return "Could not find specified socket in poll list."; 105107120Sjulian case APR_ANONYMOUS: 106107120Sjulian return "Shared memory is implemented anonymously"; 107107120Sjulian case APR_FILEBASED: 108107120Sjulian return "Shared memory is implemented using files"; 109107120Sjulian case APR_KEYBASED: 110107120Sjulian return "Shared memory is implemented using a key system"; 111107120Sjulian case APR_EINIT: 112107120Sjulian return 113107120Sjulian "There is no error, this value signifies an initialized " 114107120Sjulian "error code"; 115107120Sjulian case APR_ENOTIMPL: 116107120Sjulian return "This function has not been implemented on this platform"; 117107120Sjulian case APR_EMISMATCH: 118107120Sjulian return "passwords do not match"; 119107120Sjulian case APR_EABSOLUTE: 120107120Sjulian return "The given path is absolute"; 121107120Sjulian case APR_ERELATIVE: 122107120Sjulian return "The given path is relative"; 123107120Sjulian case APR_EINCOMPLETE: 124107120Sjulian return "The given path is incomplete"; 125107120Sjulian case APR_EABOVEROOT: 126107120Sjulian return "The given path was above the root path"; 127107120Sjulian case APR_EBADPATH: 128107120Sjulian return "The given path is misformatted or contained invalid characters"; 129107120Sjulian case APR_EPATHWILD: 130107120Sjulian return "The given path contained wildcard characters"; 131107120Sjulian case APR_EPROC_UNKNOWN: 132107120Sjulian return "The process is not recognized."; 133107120Sjulian case APR_EGENERAL: 134107120Sjulian return "Internal error"; 135107120Sjulian default: 136107120Sjulian return "Error string not specified yet"; 137107120Sjulian } 138107120Sjulian} 139107120Sjulian 140107120Sjulian 141107120Sjulian#ifdef OS2 142107120Sjulian#include <ctype.h> 143121054Semax 144107120Sjulianint apr_canonical_error(apr_status_t err); 145107120Sjulian 146107120Sjulianstatic char *apr_os_strerror(char* buf, apr_size_t bufsize, int err) 147107120Sjulian{ 148107120Sjulian char result[200]; 149107120Sjulian unsigned char message[HUGE_STRING_LEN]; 150107120Sjulian ULONG len; 151107120Sjulian char *pos; 152107120Sjulian int c; 153107120Sjulian 154107120Sjulian if (err >= 10000 && err < 12000) { /* socket error codes */ 155107120Sjulian return stuffbuffer(buf, bufsize, 156107120Sjulian strerror(apr_canonical_error(err+APR_OS_START_SYSERR))); 157107120Sjulian } 158107120Sjulian else if (DosGetMessage(NULL, 0, message, HUGE_STRING_LEN, err, 159107120Sjulian "OSO001.MSG", &len) == 0) { 160107120Sjulian len--; 161107120Sjulian message[len] = 0; 162107120Sjulian pos = result; 163107120Sjulian 164107120Sjulian if (len >= sizeof(result)) 165107120Sjulian len = sizeof(result) - 1; 166107120Sjulian 167107120Sjulian for (c=0; c<len; c++) { 168107120Sjulian /* skip multiple whitespace */ 169107120Sjulian while (apr_isspace(message[c]) && apr_isspace(message[c+1])) 170107120Sjulian c++; 171107120Sjulian *(pos++) = apr_isspace(message[c]) ? ' ' : message[c]; 172107120Sjulian } 173107120Sjulian 174107120Sjulian *pos = 0; 175107120Sjulian } 176107120Sjulian else { 177107120Sjulian sprintf(result, "OS/2 error %d", err); 178107120Sjulian } 179107120Sjulian 180107120Sjulian /* Stuff the string into the caller supplied buffer, then return 181107120Sjulian * a pointer to it. 182107120Sjulian */ 183107120Sjulian return stuffbuffer(buf, bufsize, result); 184107120Sjulian} 185107120Sjulian 186107120Sjulian#elif defined(WIN32) || (defined(NETWARE) && defined(USE_WINSOCK)) 187107120Sjulian 188107120Sjulianstatic const struct { 189107120Sjulian apr_status_t code; 190107120Sjulian const char *msg; 191107120Sjulian} gaErrorList[] = { 192107120Sjulian {WSAEINTR, "Interrupted system call"}, 193107120Sjulian {WSAEBADF, "Bad file number"}, 194107120Sjulian {WSAEACCES, "Permission denied"}, 195107120Sjulian {WSAEFAULT, "Bad address"}, 196121054Semax {WSAEINVAL, "Invalid argument"}, 197107120Sjulian {WSAEMFILE, "Too many open sockets"}, 198107120Sjulian {WSAEWOULDBLOCK, "Operation would block"}, 199107120Sjulian {WSAEINPROGRESS, "Operation now in progress"}, 200107120Sjulian {WSAEALREADY, "Operation already in progress"}, 201107120Sjulian {WSAENOTSOCK, "Socket operation on non-socket"}, 202107120Sjulian {WSAEDESTADDRREQ, "Destination address required"}, 203107120Sjulian {WSAEMSGSIZE, "Message too long"}, 204107120Sjulian {WSAEPROTOTYPE, "Protocol wrong type for socket"}, 205107120Sjulian {WSAENOPROTOOPT, "Bad protocol option"}, 206107120Sjulian {WSAEPROTONOSUPPORT, "Protocol not supported"}, 207107120Sjulian {WSAESOCKTNOSUPPORT, "Socket type not supported"}, 208107120Sjulian {WSAEOPNOTSUPP, "Operation not supported on socket"}, 209107120Sjulian {WSAEPFNOSUPPORT, "Protocol family not supported"}, 210121054Semax {WSAEAFNOSUPPORT, "Address family not supported"}, 211107120Sjulian {WSAEADDRINUSE, "Address already in use"}, 212107120Sjulian {WSAEADDRNOTAVAIL, "Can't assign requested address"}, 213107120Sjulian {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