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