errorcodes.c revision 251875
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