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 *
_gpg_strerror(gpg_error_t err)38 _gpg_strerror (gpg_error_t err)
39 {
40 gpg_err_code_t code = gpg_err_code (err);
41
42 if (code & GPG_ERR_SYSTEM_ERROR)
43 {
44 int no = gpg_err_code_to_errno (code);
45 if (no)
46 return strerror (no);
47 else
48 code = GPG_ERR_UNKNOWN_ERRNO;
49 }
50 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
system_strerror_r(int no,char * buf,size_t buflen)65 system_strerror_r (int no, char *buf, size_t buflen)
66 {
67 char *errstr;
68
69 errstr = strerror_r (no, buf, buflen);
70 if (errstr != buf)
71 {
72 size_t errstr_len = strlen (errstr) + 1;
73 size_t cpy_len = errstr_len < buflen ? errstr_len : buflen;
74 memcpy (buf, errstr, cpy_len);
75
76 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 if (strlen (buf) + 1 >= buflen)
83 return ERANGE;
84
85 return 0;
86 }
87 }
88
89 #else /* STRERROR_R_CHAR_P */
90 /* Now the POSIX version. */
91
92 static int
system_strerror_r(int no,char * buf,size_t buflen)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 #elif defined (HAVE_STRERROR_S)
100 /* Now the Windows version. */
101
102 static int
system_strerror_r(int no,char * buf,size_t buflen)103 system_strerror_r (int no, char *buf, size_t buflen)
104 {
105 return strerror_s (buf, buflen, no);
106 }
107
108 #else /* ! HAVE_STRERROR_R && ! HAVE_STRERROR_S */
109 /* Without strerror_r(), we can still provide a non-thread-safe
110 version. Maybe we are even lucky and the system's strerror() is
111 already thread-safe. */
112
113 static int
system_strerror_r(int no,char * buf,size_t buflen)114 system_strerror_r (int no, char *buf, size_t buflen)
115 {
116 char *errstr = strerror (no);
117
118 if (!errstr)
119 {
120 int saved_errno = errno;
121
122 if (saved_errno != EINVAL)
123 snprintf (buf, buflen, "strerror failed: %i\n", errno);
124 return saved_errno;
125 }
126 else
127 {
128 size_t errstr_len = strlen (errstr) + 1;
129 size_t cpy_len = errstr_len < buflen ? errstr_len : buflen;
130 memcpy (buf, errstr, cpy_len);
131 return cpy_len == errstr_len ? 0 : ERANGE;
132 }
133 }
134 #endif
135
136
137 /* Return the error string for ERR in the user-supplied buffer BUF of
138 size BUFLEN. This function is, in contrast to gpg_strerror,
139 thread-safe if a thread-safe strerror_r() function is provided by
140 the system. If the function succeeds, 0 is returned and BUF
141 contains the string describing the error. If the buffer was not
142 large enough, ERANGE is returned and BUF contains as much of the
143 beginning of the error string as fits into the buffer. */
144 int
_gpg_strerror_r(gpg_error_t err,char * buf,size_t buflen)145 _gpg_strerror_r (gpg_error_t err, char *buf, size_t buflen)
146 {
147 gpg_err_code_t code = gpg_err_code (err);
148 const char *errstr;
149 size_t errstr_len;
150 size_t cpy_len;
151
152 if (code & GPG_ERR_SYSTEM_ERROR)
153 {
154 int no = gpg_err_code_to_errno (code);
155 if (no)
156 {
157 int system_err = system_strerror_r (no, buf, buflen);
158
159 if (system_err != EINVAL)
160 {
161 if (buflen)
162 buf[buflen - 1] = '\0';
163 return system_err;
164 }
165 }
166 code = GPG_ERR_UNKNOWN_ERRNO;
167 }
168
169 errstr = dgettext (PACKAGE, msgstr + msgidx[msgidxof (code)]);
170 errstr_len = strlen (errstr) + 1;
171 cpy_len = errstr_len < buflen ? errstr_len : buflen;
172 memcpy (buf, errstr, cpy_len);
173 if (buflen)
174 buf[buflen - 1] = '\0';
175
176 return cpy_len == errstr_len ? 0 : ERANGE;
177 }
178