/src/libgpg-error/src/strerror.c
Line | Count | Source (jump to first uncovered line) |
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 | | #if defined(ENABLE_NLS) && defined(HAVE_LANGINFO_CODESET) |
36 | | #include <langinfo.h> |
37 | | #endif |
38 | | |
39 | | /* Return a pointer to a string containing a description of the error |
40 | | code in the error value ERR. This function is not thread-safe. */ |
41 | | const char * |
42 | | _gpg_strerror (gpg_error_t err) |
43 | 1.00M | { |
44 | 1.00M | gpg_err_code_t code = gpg_err_code (err); |
45 | | |
46 | 1.00M | if (code & GPG_ERR_SYSTEM_ERROR) |
47 | 108k | { |
48 | 108k | int no = gpg_err_code_to_errno (code); |
49 | 108k | if (no) |
50 | 106k | return strerror (no); |
51 | 1.80k | else |
52 | 1.80k | code = GPG_ERR_UNKNOWN_ERRNO; |
53 | 108k | } |
54 | 899k | return dgettext (PACKAGE, msgstr + msgidx[msgidxof (code)]); |
55 | 1.00M | } |
56 | | |
57 | | |
58 | | #ifdef HAVE_STRERROR_R |
59 | | #ifdef STRERROR_R_CHAR_P |
60 | | /* The GNU C library and probably some other systems have this weird |
61 | | variant of strerror_r. */ |
62 | | |
63 | | /* Return a dynamically allocated string in *STR describing the system |
64 | | error NO. If this call succeeds, return 1. If this call fails due |
65 | | to a resource shortage, set *STR to NULL and return 1. If this |
66 | | call fails because the error number is not valid, don't set *STR |
67 | | and return 0. */ |
68 | | static int |
69 | | system_strerror_r (int no, char *buf, size_t buflen) |
70 | 0 | { |
71 | 0 | char *errstr; |
72 | |
|
73 | 0 | errstr = strerror_r (no, buf, buflen); |
74 | 0 | if (errstr != buf) |
75 | 0 | { |
76 | 0 | size_t errstr_len = strlen (errstr) + 1; |
77 | 0 | size_t cpy_len = errstr_len < buflen ? errstr_len : buflen; |
78 | 0 | memcpy (buf, errstr, cpy_len); |
79 | |
|
80 | 0 | return cpy_len == errstr_len ? 0 : ERANGE; |
81 | 0 | } |
82 | 0 | else |
83 | 0 | { |
84 | | /* We can not tell if the buffer was large enough, but we can |
85 | | try to make a guess. */ |
86 | 0 | if (strlen (buf) + 1 >= buflen) |
87 | 0 | return ERANGE; |
88 | | |
89 | 0 | return 0; |
90 | 0 | } |
91 | 0 | } |
92 | | |
93 | | #else /* STRERROR_R_CHAR_P */ |
94 | | /* Now the POSIX version. */ |
95 | | |
96 | | static int |
97 | | system_strerror_r (int no, char *buf, size_t buflen) |
98 | | { |
99 | | int saved_errno; |
100 | | int r = strerror_r (no, buf, buflen); |
101 | | |
102 | | if (r) |
103 | | { |
104 | | if (r < 0) |
105 | | saved_errno = errno; |
106 | | else |
107 | | saved_errno = r; |
108 | | |
109 | | snprintf (buf, buflen, "[errno=%i]\n", r); |
110 | | return saved_errno; |
111 | | } |
112 | | |
113 | | return 0; |
114 | | } |
115 | | |
116 | | #endif /* STRERROR_R_CHAR_P */ |
117 | | #elif defined (HAVE_STRERROR_S) |
118 | | /* Now the Windows version. */ |
119 | | |
120 | | static int |
121 | | system_strerror_r (int no, char *buf, size_t buflen) |
122 | | { |
123 | | return strerror_s (buf, buflen, no); |
124 | | } |
125 | | |
126 | | #else /* ! HAVE_STRERROR_R && ! HAVE_STRERROR_S */ |
127 | | /* Without strerror_r(), we can still provide a non-thread-safe |
128 | | version. Maybe we are even lucky and the system's strerror() is |
129 | | already thread-safe. */ |
130 | | |
131 | | static int |
132 | | system_strerror_r (int no, char *buf, size_t buflen) |
133 | | { |
134 | | char *errstr = strerror (no); |
135 | | |
136 | | if (!errstr) |
137 | | { |
138 | | int saved_errno = errno; |
139 | | |
140 | | if (saved_errno != EINVAL) |
141 | | snprintf (buf, buflen, "strerror failed: %i\n", errno); |
142 | | return saved_errno; |
143 | | } |
144 | | else |
145 | | { |
146 | | size_t errstr_len = strlen (errstr) + 1; |
147 | | size_t cpy_len = errstr_len < buflen ? errstr_len : buflen; |
148 | | memcpy (buf, errstr, cpy_len); |
149 | | return cpy_len == errstr_len ? 0 : ERANGE; |
150 | | } |
151 | | } |
152 | | #endif |
153 | | |
154 | | |
155 | | /* Return the error string for ERR in the user-supplied buffer BUF of |
156 | | size BUFLEN. This function is, in contrast to gpg_strerror, |
157 | | thread-safe if a thread-safe strerror_r() function is provided by |
158 | | the system. If the function succeeds, 0 is returned and BUF |
159 | | contains the string describing the error. If the buffer was not |
160 | | large enough, ERANGE is returned and BUF contains as much of the |
161 | | beginning of the error string as fits into the buffer. */ |
162 | | int |
163 | | _gpg_strerror_r (gpg_error_t err, char *buf, size_t buflen) |
164 | 0 | { |
165 | 0 | gpg_err_code_t code = gpg_err_code (err); |
166 | 0 | const char *errstr; |
167 | 0 | size_t errstr_len; |
168 | 0 | size_t cpy_len; |
169 | |
|
170 | 0 | if (code & GPG_ERR_SYSTEM_ERROR) |
171 | 0 | { |
172 | 0 | int no = gpg_err_code_to_errno (code); |
173 | 0 | if (no) |
174 | 0 | { |
175 | 0 | int system_err = system_strerror_r (no, buf, buflen); |
176 | |
|
177 | 0 | if (system_err != EINVAL) |
178 | 0 | { |
179 | 0 | if (buflen) |
180 | 0 | buf[buflen - 1] = '\0'; |
181 | 0 | return system_err; |
182 | 0 | } |
183 | 0 | } |
184 | 0 | code = GPG_ERR_UNKNOWN_ERRNO; |
185 | 0 | } |
186 | | |
187 | 0 | errstr = dgettext (PACKAGE, msgstr + msgidx[msgidxof (code)]); |
188 | 0 | errstr_len = strlen (errstr) + 1; |
189 | 0 | cpy_len = errstr_len < buflen ? errstr_len : buflen; |
190 | 0 | #if defined(ENABLE_NLS) && defined(HAVE_LANGINFO_CODESET) |
191 | | /* Avoid truncation in the middle of "character" boundary. */ |
192 | 0 | if (buflen && errstr_len > buflen |
193 | 0 | && ((unsigned char)errstr[cpy_len-1] & 0xC0) == 0x80 |
194 | 0 | && !strcasecmp (nl_langinfo (CODESET), "UTF-8")) |
195 | 0 | { |
196 | | /* Go back to the boundary */ |
197 | 0 | for (; cpy_len; cpy_len--) |
198 | 0 | if (((unsigned char)errstr[cpy_len-1] & 0xC0) != 0x80) |
199 | 0 | break; |
200 | 0 | memcpy (buf, errstr, cpy_len); |
201 | 0 | memset (buf+cpy_len, 0, buflen - cpy_len); |
202 | 0 | } |
203 | 0 | else |
204 | 0 | { |
205 | 0 | memcpy (buf, errstr, cpy_len); |
206 | 0 | if (buflen) |
207 | 0 | buf[buflen - 1] = '\0'; |
208 | 0 | } |
209 | | #else |
210 | | memcpy (buf, errstr, cpy_len); |
211 | | if (buflen) |
212 | | buf[buflen - 1] = '\0'; |
213 | | #endif |
214 | |
|
215 | 0 | return cpy_len == errstr_len ? 0 : ERANGE; |
216 | 0 | } |