1251875Speter/* Licensed to the Apache Software Foundation (ASF) under one or more
2251875Speter * contributor license agreements.  See the NOTICE file distributed with
3251875Speter * this work for additional information regarding copyright ownership.
4251875Speter * The ASF licenses this file to You under the Apache License, Version 2.0
5251875Speter * (the "License"); you may not use this file except in compliance with
6251875Speter * the License.  You may obtain a copy of the License at
7251875Speter *
8251875Speter *     http://www.apache.org/licenses/LICENSE-2.0
9251875Speter *
10251875Speter * Unless required by applicable law or agreed to in writing, software
11251875Speter * distributed under the License is distributed on an "AS IS" BASIS,
12251875Speter * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13251875Speter * See the License for the specific language governing permissions and
14251875Speter * limitations under the License.
15251875Speter */
16251875Speter
17251875Speter#include "apr_arch_misc.h"
18251875Speter#include "apr_strings.h"
19251875Speter#include "apr_lib.h"
20251875Speter#include "apr_dso.h"
21251875Speter
22251875Speter#if APR_HAVE_NETDB_H
23251875Speter#include <netdb.h>
24251875Speter#endif
25251875Speter#ifdef HAVE_DLFCN_H
26251875Speter#include <dlfcn.h>
27251875Speter#endif
28251875Speter
29251875Speter/*
30251875Speter * stuffbuffer - like apr_cpystrn() but returns the address of the
31251875Speter * dest buffer instead of the address of the terminating '\0'
32251875Speter */
33251875Speterstatic char *stuffbuffer(char *buf, apr_size_t bufsize, const char *s)
34251875Speter{
35251875Speter    apr_cpystrn(buf,s,bufsize);
36251875Speter    return buf;
37251875Speter}
38251875Speter
39251875Speterstatic char *apr_error_string(apr_status_t statcode)
40251875Speter{
41251875Speter    switch (statcode) {
42289166Speter    case APR_ENOSTAT:
43289166Speter        return "Could not perform a stat on the file.";
44251875Speter    case APR_ENOPOOL:
45251875Speter        return "A new pool could not be created.";
46251875Speter    case APR_EBADDATE:
47251875Speter        return "An invalid date has been provided";
48251875Speter    case APR_EINVALSOCK:
49251875Speter        return "An invalid socket was returned";
50251875Speter    case APR_ENOPROC:
51251875Speter        return "No process was provided and one was required.";
52251875Speter    case APR_ENOTIME:
53251875Speter        return "No time was provided and one was required.";
54251875Speter    case APR_ENODIR:
55251875Speter        return "No directory was provided and one was required.";
56251875Speter    case APR_ENOLOCK:
57251875Speter        return "No lock was provided and one was required.";
58251875Speter    case APR_ENOPOLL:
59251875Speter        return "No poll structure was provided and one was required.";
60251875Speter    case APR_ENOSOCKET:
61251875Speter        return "No socket was provided and one was required.";
62251875Speter    case APR_ENOTHREAD:
63251875Speter        return "No thread was provided and one was required.";
64251875Speter    case APR_ENOTHDKEY:
65251875Speter        return "No thread key structure was provided and one was required.";
66251875Speter    case APR_ENOSHMAVAIL:
67251875Speter        return "No shared memory is currently available";
68251875Speter    case APR_EDSOOPEN:
69251875Speter#if APR_HAS_DSO && defined(HAVE_LIBDL)
70251875Speter        return dlerror();
71251875Speter#else
72251875Speter        return "DSO load failed";
73251875Speter#endif /* HAVE_LIBDL */
74251875Speter    case APR_EBADIP:
75251875Speter        return "The specified IP address is invalid.";
76251875Speter    case APR_EBADMASK:
77251875Speter        return "The specified network mask is invalid.";
78289166Speter    case APR_ESYMNOTFOUND:
79289166Speter        return "Could not find the requested symbol.";
80289166Speter    case APR_ENOTENOUGHENTROPY:
81289166Speter        return "Not enough entropy to continue.";
82251875Speter    case APR_INCHILD:
83251875Speter        return
84251875Speter	    "Your code just forked, and you are currently executing in the "
85251875Speter	    "child process";
86251875Speter    case APR_INPARENT:
87251875Speter        return
88251875Speter	    "Your code just forked, and you are currently executing in the "
89251875Speter	    "parent process";
90251875Speter    case APR_DETACH:
91251875Speter        return "The specified thread is detached";
92251875Speter    case APR_NOTDETACH:
93251875Speter        return "The specified thread is not detached";
94251875Speter    case APR_CHILD_DONE:
95251875Speter        return "The specified child process is done executing";
96251875Speter    case APR_CHILD_NOTDONE:
97251875Speter        return "The specified child process is not done executing";
98251875Speter    case APR_TIMEUP:
99251875Speter        return "The timeout specified has expired";
100251875Speter    case APR_INCOMPLETE:
101251875Speter        return "Partial results are valid but processing is incomplete";
102251875Speter    case APR_BADCH:
103251875Speter        return "Bad character specified on command line";
104251875Speter    case APR_BADARG:
105251875Speter        return "Missing parameter for the specified command line option";
106251875Speter    case APR_EOF:
107251875Speter        return "End of file found";
108251875Speter    case APR_NOTFOUND:
109251875Speter        return "Could not find specified socket in poll list.";
110251875Speter    case APR_ANONYMOUS:
111251875Speter        return "Shared memory is implemented anonymously";
112251875Speter    case APR_FILEBASED:
113251875Speter        return "Shared memory is implemented using files";
114251875Speter    case APR_KEYBASED:
115251875Speter        return "Shared memory is implemented using a key system";
116251875Speter    case APR_EINIT:
117251875Speter        return
118251875Speter	    "There is no error, this value signifies an initialized "
119251875Speter	    "error code";
120251875Speter    case APR_ENOTIMPL:
121251875Speter        return "This function has not been implemented on this platform";
122251875Speter    case APR_EMISMATCH:
123251875Speter        return "passwords do not match";
124251875Speter    case APR_EABSOLUTE:
125251875Speter        return "The given path is absolute";
126251875Speter    case APR_ERELATIVE:
127251875Speter        return "The given path is relative";
128251875Speter    case APR_EINCOMPLETE:
129251875Speter        return "The given path is incomplete";
130251875Speter    case APR_EABOVEROOT:
131251875Speter        return "The given path was above the root path";
132251875Speter    case APR_EBADPATH:
133251875Speter        return "The given path is misformatted or contained invalid characters";
134251875Speter    case APR_EPATHWILD:
135251875Speter        return "The given path contained wildcard characters";
136289166Speter    case APR_EBUSY:
137289166Speter        return "The given lock was busy.";
138251875Speter    case APR_EPROC_UNKNOWN:
139251875Speter        return "The process is not recognized.";
140251875Speter    case APR_EGENERAL:
141289166Speter        return "Internal error (specific information not available)";
142251875Speter    default:
143251875Speter        return "Error string not specified yet";
144251875Speter    }
145251875Speter}
146251875Speter
147251875Speter
148251875Speter#ifdef OS2
149251875Speter#include <ctype.h>
150251875Speter
151251875Speterint apr_canonical_error(apr_status_t err);
152251875Speter
153251875Speterstatic char *apr_os_strerror(char* buf, apr_size_t bufsize, int err)
154251875Speter{
155251875Speter  char result[200];
156251875Speter  unsigned char message[HUGE_STRING_LEN];
157251875Speter  ULONG len;
158251875Speter  char *pos;
159251875Speter  int c;
160251875Speter
161251875Speter  if (err >= 10000 && err < 12000) {  /* socket error codes */
162251875Speter      return stuffbuffer(buf, bufsize,
163251875Speter                         strerror(apr_canonical_error(err+APR_OS_START_SYSERR)));
164251875Speter  }
165251875Speter  else if (DosGetMessage(NULL, 0, message, HUGE_STRING_LEN, err,
166251875Speter			 "OSO001.MSG", &len) == 0) {
167251875Speter      len--;
168251875Speter      message[len] = 0;
169251875Speter      pos = result;
170251875Speter
171251875Speter      if (len >= sizeof(result))
172251875Speter        len = sizeof(result) - 1;
173251875Speter
174251875Speter      for (c=0; c<len; c++) {
175251875Speter	  /* skip multiple whitespace */
176251875Speter          while (apr_isspace(message[c]) && apr_isspace(message[c+1]))
177251875Speter              c++;
178251875Speter          *(pos++) = apr_isspace(message[c]) ? ' ' : message[c];
179251875Speter      }
180251875Speter
181251875Speter      *pos = 0;
182251875Speter  }
183251875Speter  else {
184251875Speter      sprintf(result, "OS/2 error %d", err);
185251875Speter  }
186251875Speter
187251875Speter  /* Stuff the string into the caller supplied buffer, then return
188251875Speter   * a pointer to it.
189251875Speter   */
190251875Speter  return stuffbuffer(buf, bufsize, result);
191251875Speter}
192251875Speter
193251875Speter#elif defined(WIN32) || (defined(NETWARE) && defined(USE_WINSOCK))
194251875Speter
195251875Speterstatic const struct {
196251875Speter    apr_status_t code;
197251875Speter    const char *msg;
198251875Speter} gaErrorList[] = {
199251875Speter    {WSAEINTR,           "Interrupted system call"},
200251875Speter    {WSAEBADF,           "Bad file number"},
201251875Speter    {WSAEACCES,          "Permission denied"},
202251875Speter    {WSAEFAULT,          "Bad address"},
203251875Speter    {WSAEINVAL,          "Invalid argument"},
204251875Speter    {WSAEMFILE,          "Too many open sockets"},
205251875Speter    {WSAEWOULDBLOCK,     "Operation would block"},
206251875Speter    {WSAEINPROGRESS,     "Operation now in progress"},
207251875Speter    {WSAEALREADY,        "Operation already in progress"},
208251875Speter    {WSAENOTSOCK,        "Socket operation on non-socket"},
209251875Speter    {WSAEDESTADDRREQ,    "Destination address required"},
210251875Speter    {WSAEMSGSIZE,        "Message too long"},
211251875Speter    {WSAEPROTOTYPE,      "Protocol wrong type for socket"},
212251875Speter    {WSAENOPROTOOPT,     "Bad protocol option"},
213251875Speter    {WSAEPROTONOSUPPORT, "Protocol not supported"},
214251875Speter    {WSAESOCKTNOSUPPORT, "Socket type not supported"},
215251875Speter    {WSAEOPNOTSUPP,      "Operation not supported on socket"},
216251875Speter    {WSAEPFNOSUPPORT,    "Protocol family not supported"},
217251875Speter    {WSAEAFNOSUPPORT,    "Address family not supported"},
218251875Speter    {WSAEADDRINUSE,      "Address already in use"},
219251875Speter    {WSAEADDRNOTAVAIL,   "Can't assign requested address"},
220251875Speter    {WSAENETDOWN,        "Network is down"},
221251875Speter    {WSAENETUNREACH,     "Network is unreachable"},
222251875Speter    {WSAENETRESET,       "Net connection reset"},
223251875Speter    {WSAECONNABORTED,    "Software caused connection abort"},
224251875Speter    {WSAECONNRESET,      "Connection reset by peer"},
225251875Speter    {WSAENOBUFS,         "No buffer space available"},
226251875Speter    {WSAEISCONN,         "Socket is already connected"},
227251875Speter    {WSAENOTCONN,        "Socket is not connected"},
228251875Speter    {WSAESHUTDOWN,       "Can't send after socket shutdown"},
229251875Speter    {WSAETOOMANYREFS,    "Too many references, can't splice"},
230251875Speter    {WSAETIMEDOUT,       "Connection timed out"},
231251875Speter    {WSAECONNREFUSED,    "Connection refused"},
232251875Speter    {WSAELOOP,           "Too many levels of symbolic links"},
233251875Speter    {WSAENAMETOOLONG,    "File name too long"},
234251875Speter    {WSAEHOSTDOWN,       "Host is down"},
235251875Speter    {WSAEHOSTUNREACH,    "No route to host"},
236251875Speter    {WSAENOTEMPTY,       "Directory not empty"},
237251875Speter    {WSAEPROCLIM,        "Too many processes"},
238251875Speter    {WSAEUSERS,          "Too many users"},
239251875Speter    {WSAEDQUOT,          "Disc quota exceeded"},
240251875Speter    {WSAESTALE,          "Stale NFS file handle"},
241251875Speter    {WSAEREMOTE,         "Too many levels of remote in path"},
242251875Speter    {WSASYSNOTREADY,     "Network system is unavailable"},
243251875Speter    {WSAVERNOTSUPPORTED, "Winsock version out of range"},
244251875Speter    {WSANOTINITIALISED,  "WSAStartup not yet called"},
245251875Speter    {WSAEDISCON,         "Graceful shutdown in progress"},
246251875Speter    {WSAHOST_NOT_FOUND,  "Host not found"},
247251875Speter    {WSANO_DATA,         "No host data of that type was found"},
248251875Speter    {0,                  NULL}
249251875Speter};
250251875Speter
251251875Speter
252251875Speterstatic char *apr_os_strerror(char *buf, apr_size_t bufsize, apr_status_t errcode)
253251875Speter{
254251875Speter    apr_size_t len=0, i;
255251875Speter
256251875Speter#ifndef NETWARE
257251875Speter#ifndef _WIN32_WCE
258251875Speter    len = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM
259251875Speter                      | FORMAT_MESSAGE_IGNORE_INSERTS,
260251875Speter                        NULL,
261251875Speter                        errcode,
262251875Speter                        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
263251875Speter                        buf,
264251875Speter                        (DWORD)bufsize,
265251875Speter                        NULL);
266251875Speter#else /* _WIN32_WCE speaks unicode */
267251875Speter     LPTSTR msg = (LPTSTR) buf;
268251875Speter     len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
269251875Speter                       | FORMAT_MESSAGE_IGNORE_INSERTS,
270251875Speter                         NULL,
271251875Speter                         errcode,
272251875Speter                         MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
273251875Speter                         msg,
274251875Speter                         (DWORD) (bufsize/sizeof(TCHAR)),
275251875Speter                         NULL);
276251875Speter     /* in-place convert to US-ASCII, substituting '?' for non ASCII   */
277251875Speter     for(i = 0; i <= len; i++) {
278251875Speter        if (msg[i] < 0x80 && msg[i] >= 0) {
279251875Speter            buf[i] = (char) msg[i];
280251875Speter        } else {
281251875Speter            buf[i] = '?';
282251875Speter        }
283251875Speter    }
284251875Speter#endif
285251875Speter#endif
286251875Speter
287251875Speter    if (!len) {
288251875Speter        for (i = 0; gaErrorList[i].msg; ++i) {
289251875Speter            if (gaErrorList[i].code == errcode) {
290251875Speter                apr_cpystrn(buf, gaErrorList[i].msg, bufsize);
291251875Speter                len = strlen(buf);
292251875Speter                break;
293251875Speter            }
294251875Speter        }
295251875Speter    }
296251875Speter
297251875Speter    if (len) {
298251875Speter        /* FormatMessage put the message in the buffer, but it may
299251875Speter         * have embedded a newline (\r\n), and possible more than one.
300251875Speter         * Remove the newlines replacing them with a space. This is not
301251875Speter         * as visually perfect as moving all the remaining message over,
302251875Speter         * but more efficient.
303251875Speter         */
304251875Speter        i = len;
305251875Speter        while (i) {
306251875Speter            i--;
307251875Speter            if ((buf[i] == '\r') || (buf[i] == '\n'))
308251875Speter                buf[i] = ' ';
309251875Speter        }
310251875Speter    }
311251875Speter    else {
312251875Speter        /* Windows didn't provide us with a message.  Even stuff like                    * WSAECONNREFUSED won't get a message.
313251875Speter         */
314251875Speter        apr_snprintf(buf, bufsize, "Unrecognized Win32 error code %d", errcode);
315251875Speter    }
316251875Speter
317251875Speter    return buf;
318251875Speter}
319251875Speter
320251875Speter#else
321251875Speter/* On Unix, apr_os_strerror() handles error codes from the resolver
322251875Speter * (h_errno).
323251875Speter */
324251875Speterstatic char *apr_os_strerror(char* buf, apr_size_t bufsize, int err)
325251875Speter{
326251875Speter#ifdef HAVE_HSTRERROR
327251875Speter    return stuffbuffer(buf, bufsize, hstrerror(err));
328251875Speter#else /* HAVE_HSTRERROR */
329251875Speter    const char *msg;
330251875Speter
331251875Speter    switch(err) {
332251875Speter    case HOST_NOT_FOUND:
333251875Speter        msg = "Unknown host";
334251875Speter        break;
335251875Speter#if defined(NO_DATA)
336251875Speter    case NO_DATA:
337251875Speter#if defined(NO_ADDRESS) && (NO_DATA != NO_ADDRESS)
338251875Speter    case NO_ADDRESS:
339251875Speter#endif
340251875Speter        msg = "No address for host";
341251875Speter        break;
342251875Speter#elif defined(NO_ADDRESS)
343251875Speter    case NO_ADDRESS:
344251875Speter        msg = "No address for host";
345251875Speter        break;
346251875Speter#endif /* NO_DATA */
347251875Speter    default:
348251875Speter        msg = "Unrecognized resolver error";
349251875Speter    }
350251875Speter    return stuffbuffer(buf, bufsize, msg);
351251875Speter#endif /* HAVE_STRERROR */
352251875Speter}
353251875Speter#endif
354251875Speter
355251875Speter#if defined(HAVE_STRERROR_R) && defined(STRERROR_R_RC_INT) && !defined(BEOS)
356251875Speter/* AIX and Tru64 style */
357251875Speterstatic char *native_strerror(apr_status_t statcode, char *buf,
358251875Speter                             apr_size_t bufsize)
359251875Speter{
360251875Speter    if (strerror_r(statcode, buf, bufsize) < 0) {
361251875Speter        return stuffbuffer(buf, bufsize,
362251875Speter                           "APR does not understand this error code");
363251875Speter    }
364251875Speter    else {
365251875Speter        return buf;
366251875Speter    }
367251875Speter}
368251875Speter#elif defined(HAVE_STRERROR_R)
369251875Speter/* glibc style */
370251875Speter
371251875Speter/* BeOS has the function available, but it doesn't provide
372251875Speter * the prototype publically (doh!), so to avoid a build warning
373251875Speter * we add a suitable prototype here.
374251875Speter */
375251875Speter#if defined(BEOS)
376251875Speterconst char *strerror_r(apr_status_t, char *, apr_size_t);
377251875Speter#endif
378251875Speter
379251875Speterstatic char *native_strerror(apr_status_t statcode, char *buf,
380251875Speter                             apr_size_t bufsize)
381251875Speter{
382251875Speter    const char *msg;
383251875Speter
384251875Speter    buf[0] = '\0';
385251875Speter    msg = strerror_r(statcode, buf, bufsize);
386251875Speter    if (buf[0] == '\0') { /* libc didn't use our buffer */
387251875Speter        return stuffbuffer(buf, bufsize, msg);
388251875Speter    }
389251875Speter    else {
390251875Speter        return buf;
391251875Speter    }
392251875Speter}
393251875Speter#else
394251875Speter/* plain old strerror();
395251875Speter * thread-safe on some platforms (e.g., Solaris, OS/390)
396251875Speter */
397251875Speterstatic char *native_strerror(apr_status_t statcode, char *buf,
398251875Speter                             apr_size_t bufsize)
399251875Speter{
400251875Speter#ifdef _WIN32_WCE
401251875Speter    static char err[32];
402251875Speter    sprintf(err, "Native Error #%d", statcode);
403251875Speter    return stuffbuffer(buf, bufsize, err);
404251875Speter#else
405251875Speter    const char *err = strerror(statcode);
406251875Speter    if (err) {
407251875Speter        return stuffbuffer(buf, bufsize, err);
408251875Speter    } else {
409251875Speter        return stuffbuffer(buf, bufsize,
410251875Speter                           "APR does not understand this error code");
411251875Speter    }
412251875Speter#endif
413251875Speter}
414251875Speter#endif
415251875Speter
416251875SpeterAPR_DECLARE(char *) apr_strerror(apr_status_t statcode, char *buf,
417251875Speter                                 apr_size_t bufsize)
418251875Speter{
419251875Speter    if (statcode < APR_OS_START_ERROR) {
420251875Speter        return native_strerror(statcode, buf, bufsize);
421251875Speter    }
422251875Speter    else if (statcode < APR_OS_START_USERERR) {
423251875Speter        return stuffbuffer(buf, bufsize, apr_error_string(statcode));
424251875Speter    }
425251875Speter    else if (statcode < APR_OS_START_EAIERR) {
426251875Speter        return stuffbuffer(buf, bufsize, "APR does not understand this error code");
427251875Speter    }
428251875Speter    else if (statcode < APR_OS_START_SYSERR) {
429251875Speter#if defined(HAVE_GAI_STRERROR)
430251875Speter        statcode -= APR_OS_START_EAIERR;
431251875Speter#if defined(NEGATIVE_EAI)
432251875Speter        statcode = -statcode;
433251875Speter#endif
434251875Speter        return stuffbuffer(buf, bufsize, gai_strerror(statcode));
435251875Speter#else
436251875Speter        return stuffbuffer(buf, bufsize, "APR does not understand this error code");
437251875Speter#endif
438251875Speter    }
439251875Speter    else {
440251875Speter        return apr_os_strerror(buf, bufsize, statcode - APR_OS_START_SYSERR);
441251875Speter    }
442251875Speter}
443251875Speter
444