Coverage Report

Created: 2022-12-08 06:10

/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
}