Line data Source code
1 : /* strerror.c - Describing an error code.
2 : Copyright (C) 2003 g10 Code GmbH
3 :
4 : This file is part of libgpg-error.
5 :
6 : libgpg-error is free software; you can redistribute it and/or
7 : modify it under the terms of the GNU Lesser General Public License
8 : as published by the Free Software Foundation; either version 2.1 of
9 : the License, or (at your option) any later version.
10 :
11 : libgpg-error is distributed in the hope that it will be useful, but
12 : WITHOUT ANY WARRANTY; without even the implied warranty of
13 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : Lesser General Public License for more details.
15 :
16 : You should have received a copy of the GNU Lesser General Public
17 : License along with libgpg-error; if not, write to the Free
18 : Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 : 02111-1307, USA. */
20 :
21 : #if HAVE_CONFIG_H
22 : #include <config.h>
23 : #endif
24 :
25 : #include <stdlib.h>
26 : #include <stdio.h>
27 : #include <string.h>
28 : #include <errno.h>
29 :
30 : #include <gpg-error.h>
31 :
32 : #include "gettext.h"
33 : #include "err-codes.h"
34 :
35 : /* Return a pointer to a string containing a description of the error
36 : code in the error value ERR. This function is not thread-safe. */
37 : const char *
38 0 : _gpg_strerror (gpg_error_t err)
39 : {
40 : gpg_err_code_t code = gpg_err_code (err);
41 :
42 0 : if (code & GPG_ERR_SYSTEM_ERROR)
43 : {
44 0 : int no = gpg_err_code_to_errno (code);
45 0 : if (no)
46 0 : return strerror (no);
47 : else
48 : code = GPG_ERR_UNKNOWN_ERRNO;
49 : }
50 0 : return dgettext (PACKAGE, msgstr + msgidx[msgidxof (code)]);
51 : }
52 :
53 :
54 : #ifdef HAVE_STRERROR_R
55 : #ifdef STRERROR_R_CHAR_P
56 : /* The GNU C library and probably some other systems have this weird
57 : variant of strerror_r. */
58 :
59 : /* Return a dynamically allocated string in *STR describing the system
60 : error NO. If this call succeeds, return 1. If this call fails due
61 : to a resource shortage, set *STR to NULL and return 1. If this
62 : call fails because the error number is not valid, don't set *STR
63 : and return 0. */
64 : static int
65 0 : system_strerror_r (int no, char *buf, size_t buflen)
66 : {
67 : char *errstr;
68 :
69 0 : errstr = strerror_r (no, buf, buflen);
70 0 : if (errstr != buf)
71 : {
72 0 : size_t errstr_len = strlen (errstr) + 1;
73 0 : size_t cpy_len = errstr_len < buflen ? errstr_len : buflen;
74 0 : memcpy (buf, errstr, cpy_len);
75 :
76 0 : return cpy_len == errstr_len ? 0 : ERANGE;
77 : }
78 : else
79 : {
80 : /* We can not tell if the buffer was large enough, but we can
81 : try to make a guess. */
82 0 : if (strlen (buf) + 1 >= buflen)
83 : return ERANGE;
84 :
85 0 : return 0;
86 : }
87 : }
88 :
89 : #else /* STRERROR_R_CHAR_P */
90 : /* Now the POSIX version. */
91 :
92 : static int
93 : system_strerror_r (int no, char *buf, size_t buflen)
94 : {
95 : return strerror_r (no, buf, buflen);
96 : }
97 :
98 : #endif /* STRERROR_R_CHAR_P */
99 :
100 : #else /* HAVE_STRERROR_H */
101 : /* Without strerror_r(), we can still provide a non-thread-safe
102 : version. Maybe we are even lucky and the system's strerror() is
103 : already thread-safe. */
104 :
105 : static int
106 : system_strerror_r (int no, char *buf, size_t buflen)
107 : {
108 : char *errstr = strerror (no);
109 :
110 : if (!errstr)
111 : {
112 : int saved_errno = errno;
113 :
114 : if (saved_errno != EINVAL)
115 : snprintf (buf, buflen, "strerror failed: %i\n", errno);
116 : return saved_errno;
117 : }
118 : else
119 : {
120 : size_t errstr_len = strlen (errstr) + 1;
121 : size_t cpy_len = errstr_len < buflen ? errstr_len : buflen;
122 : memcpy (buf, errstr, cpy_len);
123 : return cpy_len == errstr_len ? 0 : ERANGE;
124 : }
125 : }
126 : #endif
127 :
128 :
129 : /* Return the error string for ERR in the user-supplied buffer BUF of
130 : size BUFLEN. This function is, in contrast to gpg_strerror,
131 : thread-safe if a thread-safe strerror_r() function is provided by
132 : the system. If the function succeeds, 0 is returned and BUF
133 : contains the string describing the error. If the buffer was not
134 : large enough, ERANGE is returned and BUF contains as much of the
135 : beginning of the error string as fits into the buffer. */
136 : int
137 0 : _gpg_strerror_r (gpg_error_t err, char *buf, size_t buflen)
138 : {
139 : gpg_err_code_t code = gpg_err_code (err);
140 : const char *errstr;
141 : size_t errstr_len;
142 : size_t cpy_len;
143 :
144 0 : if (code & GPG_ERR_SYSTEM_ERROR)
145 : {
146 0 : int no = gpg_err_code_to_errno (code);
147 0 : if (no)
148 : {
149 0 : int system_err = system_strerror_r (no, buf, buflen);
150 :
151 0 : if (system_err != EINVAL)
152 : {
153 0 : if (buflen)
154 0 : buf[buflen - 1] = '\0';
155 : return system_err;
156 : }
157 : }
158 : code = GPG_ERR_UNKNOWN_ERRNO;
159 : }
160 :
161 0 : errstr = dgettext (PACKAGE, msgstr + msgidx[msgidxof (code)]);
162 0 : errstr_len = strlen (errstr) + 1;
163 0 : cpy_len = errstr_len < buflen ? errstr_len : buflen;
164 0 : memcpy (buf, errstr, cpy_len);
165 0 : if (buflen)
166 0 : buf[buflen - 1] = '\0';
167 :
168 0 : return cpy_len == errstr_len ? 0 : ERANGE;
169 : }
|