Line data Source code
1 : /* gpg-error.c - Determining gpg-error error codes.
2 : Copyright (C) 2004, 2016 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 <stddef.h>
26 : #include <stdlib.h>
27 : #include <string.h>
28 : #include <errno.h>
29 : #include <limits.h>
30 : #include <stdio.h>
31 :
32 : #ifdef HAVE_LOCALE_H
33 : # include <locale.h>
34 : #endif
35 : #ifdef ENABLE_NLS
36 : #ifdef HAVE_W32_SYSTEM
37 : # include "gettext.h"
38 : #else
39 : # include <libintl.h>
40 : #endif
41 : # define _(a) gettext (a)
42 : # ifdef gettext_noop
43 : # define N_(a) gettext_noop (a)
44 : # else
45 : # define N_(a) (a)
46 : # endif
47 : #else
48 : # define _(a) (a)
49 : # define N_(a) (a)
50 : #endif
51 :
52 : #include <gpg-error.h>
53 :
54 :
55 : #if HAVE_W32_SYSTEM
56 : /* The implementation follows below. */
57 : static char *get_locale_dir (void);
58 : static void drop_locale_dir (char *locale_dir);
59 : #else
60 : #define get_locale_dir() LOCALEDIR
61 : #define drop_locale_dir(dir)
62 : #endif
63 :
64 : static void
65 0 : i18n_init (void)
66 : {
67 : #ifdef ENABLE_NLS
68 : char *locale_dir;
69 :
70 : #ifdef HAVE_LC_MESSAGES
71 : setlocale (LC_TIME, "");
72 : setlocale (LC_MESSAGES, "");
73 : #else
74 : # ifndef HAVE_W32_SYSTEM
75 0 : setlocale (LC_ALL, "" );
76 : # endif
77 : #endif
78 :
79 : /* Note that for this program we would only need the textdomain call
80 : because libgpg-error already initializes itself to its locale dir
81 : (via gpg_err_init or a constructor). However this is only done
82 : for the static standard locale and thus if the above setlocale
83 : calls select a different locale the bindtext below will do
84 : something else. */
85 :
86 : locale_dir = get_locale_dir ();
87 : if (locale_dir)
88 : {
89 0 : bindtextdomain (PACKAGE, locale_dir);
90 : drop_locale_dir (locale_dir);
91 : }
92 0 : textdomain (PACKAGE);
93 : #endif
94 0 : }
95 :
96 :
97 : #ifdef HAVE_W32_SYSTEM
98 :
99 : #include <windows.h>
100 :
101 :
102 : static char *
103 : get_locale_dir (void)
104 : {
105 : static wchar_t moddir[MAX_PATH+5];
106 : char *result, *p;
107 : int nbytes;
108 :
109 : if (!GetModuleFileNameW (NULL, moddir, MAX_PATH))
110 : *moddir = 0;
111 :
112 : #define SLDIR "\\share\\locale"
113 : if (*moddir)
114 : {
115 : nbytes = WideCharToMultiByte (CP_UTF8, 0, moddir, -1, NULL, 0, NULL, NULL);
116 : if (nbytes < 0)
117 : return NULL;
118 :
119 : result = malloc (nbytes + strlen (SLDIR) + 1);
120 : if (result)
121 : {
122 : nbytes = WideCharToMultiByte (CP_UTF8, 0, moddir, -1,
123 : result, nbytes, NULL, NULL);
124 : if (nbytes < 0)
125 : {
126 : free (result);
127 : result = NULL;
128 : }
129 : else
130 : {
131 : p = strrchr (result, '\\');
132 : if (p)
133 : *p = 0;
134 : /* If we are installed below "bin" strip that part and
135 : use the top directory instead. */
136 : p = strrchr (result, '\\');
137 : if (p && !strcmp (p+1, "bin"))
138 : *p = 0;
139 : /* Append the static part. */
140 : strcat (result, SLDIR);
141 : }
142 : }
143 : }
144 : else /* Use the old default value. */
145 : {
146 : result = malloc (10 + strlen (SLDIR) + 1);
147 : if (result)
148 : {
149 : strcpy (result, "c:\\gnupg");
150 : strcat (result, SLDIR);
151 : }
152 : }
153 : #undef SLDIR
154 : return result;
155 : }
156 :
157 :
158 : static void
159 : drop_locale_dir (char *locale_dir)
160 : {
161 : free (locale_dir);
162 : }
163 :
164 : #endif /* HAVE_W32_SYSTEM */
165 :
166 :
167 : const char *gpg_strerror_sym (gpg_error_t err);
168 : const char *gpg_strsource_sym (gpg_error_t err);
169 :
170 :
171 : static int
172 0 : get_err_from_number (char *str, gpg_error_t *err)
173 : {
174 : unsigned long nr;
175 : char *tail;
176 :
177 0 : gpg_err_set_errno (0);
178 0 : nr = strtoul (str, &tail, 0);
179 0 : if (errno)
180 : return 0;
181 :
182 0 : if (nr > UINT_MAX)
183 : return 0;
184 :
185 0 : if (*tail)
186 : {
187 0 : unsigned long cnr = strtoul (tail + 1, &tail, 0);
188 0 : if (errno || *tail)
189 : return 0;
190 :
191 0 : if (nr >= GPG_ERR_SOURCE_DIM || cnr >= GPG_ERR_CODE_DIM)
192 : return 0;
193 :
194 0 : nr = gpg_err_make (nr, cnr);
195 : }
196 :
197 0 : *err = (unsigned int) nr;
198 0 : return 1;
199 : }
200 :
201 :
202 : static int
203 0 : get_err_from_symbol_one (char *str, gpg_error_t *err,
204 : int *have_source, int *have_code)
205 : {
206 : static const char src_prefix[] = "GPG_ERR_SOURCE_";
207 : static const char code_prefix[] = "GPG_ERR_";
208 :
209 0 : if (!strncasecmp (src_prefix, str, sizeof (src_prefix) - 1))
210 : {
211 : gpg_err_source_t src;
212 :
213 0 : if (*have_source)
214 : return 0;
215 0 : *have_source = 1;
216 0 : str += sizeof (src_prefix) - 1;
217 :
218 0 : for (src = 0; src < GPG_ERR_SOURCE_DIM; src++)
219 : {
220 : const char *src_sym;
221 :
222 0 : src_sym = gpg_strsource_sym (src << GPG_ERR_SOURCE_SHIFT);
223 0 : if (src_sym && !strcasecmp (str, src_sym + sizeof (src_prefix) - 1))
224 : {
225 0 : *err |= src << GPG_ERR_SOURCE_SHIFT;
226 0 : return 1;
227 : }
228 : }
229 : }
230 0 : else if (!strncasecmp (code_prefix, str, sizeof (code_prefix) - 1))
231 : {
232 : gpg_err_code_t code;
233 :
234 0 : if (*have_code)
235 : return 0;
236 0 : *have_code = 1;
237 0 : str += sizeof (code_prefix) - 1;
238 :
239 0 : for (code = 0; code < GPG_ERR_CODE_DIM; code++)
240 : {
241 0 : const char *code_sym = gpg_strerror_sym (code);
242 0 : if (code_sym
243 0 : && !strcasecmp (str, code_sym + sizeof (code_prefix) - 1))
244 : {
245 0 : *err |= code;
246 0 : return 1;
247 : }
248 : }
249 : }
250 : return 0;
251 : }
252 :
253 :
254 : static int
255 0 : get_err_from_symbol (char *str, gpg_error_t *err)
256 : {
257 : char *str2 = str;
258 0 : int have_source = 0;
259 0 : int have_code = 0;
260 : int ret;
261 : char *saved_pos = NULL;
262 : char saved_char;
263 :
264 0 : *err = 0;
265 0 : while (*str2 && ((*str2 >= 'A' && *str2 <= 'Z')
266 0 : || (*str2 >= '0' && *str2 <= '9')
267 0 : || *str2 == '_'))
268 0 : str2++;
269 0 : if (*str2)
270 : {
271 : saved_pos = str2;
272 : saved_char = *str2;
273 0 : *str2 = '\0';
274 0 : str2++;
275 : }
276 : else
277 : str2 = NULL;
278 :
279 0 : ret = get_err_from_symbol_one (str, err, &have_source, &have_code);
280 0 : if (ret && str2)
281 0 : ret = get_err_from_symbol_one (str2, err, &have_source, &have_code);
282 :
283 0 : if (saved_pos)
284 0 : *saved_pos = saved_char;
285 0 : return ret;
286 : }
287 :
288 :
289 : static int
290 0 : get_err_from_str_one (char *str, gpg_error_t *err,
291 : int *have_source, int *have_code)
292 : {
293 : gpg_err_source_t src;
294 : gpg_err_code_t code;
295 :
296 0 : for (src = 0; src < GPG_ERR_SOURCE_DIM; src++)
297 : {
298 0 : const char *src_str = gpg_strsource (src << GPG_ERR_SOURCE_SHIFT);
299 0 : if (src_str && !strcasecmp (str, src_str))
300 : {
301 0 : if (*have_source)
302 : return 0;
303 :
304 0 : *have_source = 1;
305 0 : *err |= src << GPG_ERR_SOURCE_SHIFT;
306 0 : return 1;
307 : }
308 : }
309 :
310 0 : for (code = 0; code < GPG_ERR_CODE_DIM; code++)
311 : {
312 0 : const char *code_str = gpg_strerror (code);
313 0 : if (code_str && !strcasecmp (str, code_str))
314 : {
315 0 : if (*have_code)
316 : return 0;
317 :
318 0 : *have_code = 1;
319 0 : *err |= code;
320 0 : return 1;
321 : }
322 : }
323 :
324 : return 0;
325 : }
326 :
327 :
328 : static int
329 0 : get_err_from_str (char *str, gpg_error_t *err)
330 : {
331 : char *str2 = str;
332 0 : int have_source = 0;
333 0 : int have_code = 0;
334 : int ret;
335 : char *saved_pos = NULL;
336 : char saved_char = 0; /* (avoid warning) */
337 :
338 0 : *err = 0;
339 0 : ret = get_err_from_str_one (str, err, &have_source, &have_code);
340 0 : if (ret)
341 : return ret;
342 :
343 0 : while (*str2 && ((*str2 >= 'A' && *str2 <= 'Z')
344 0 : || (*str2 >= 'a' && *str2 <= 'z')
345 0 : || (*str2 >= '0' && *str2 <= '9')
346 0 : || *str2 == '_'))
347 0 : str2++;
348 0 : if (*str2)
349 : {
350 : saved_pos = str2;
351 : saved_char = *str2;
352 0 : *((char *) str2) = '\0';
353 0 : str2++;
354 0 : while (*str2 && !((*str2 >= 'A' && *str2 <= 'Z')
355 0 : || (*str2 >= 'a' && *str2 <= 'z')
356 0 : || (*str2 >= '0' && *str2 <= '9')
357 : || *str2 == '_'))
358 0 : str2++;
359 : }
360 : else
361 : str2 = NULL;
362 :
363 0 : ret = get_err_from_str_one (str, err, &have_source, &have_code);
364 0 : if (ret && str2)
365 0 : ret = get_err_from_str_one (str2, err, &have_source, &have_code);
366 :
367 0 : if (saved_pos)
368 0 : *saved_pos = saved_char;
369 : return ret;
370 : }
371 :
372 :
373 : static void
374 0 : print_desc (const char *symbol)
375 : {
376 : static int initialized;
377 : static FILE *fp;
378 : char line[512];
379 : char *p;
380 : int indesc = 0;
381 : int blanklines = 0;
382 : int last_was_keyword = 0;
383 :
384 0 : if (!symbol)
385 0 : return;
386 :
387 0 : if (!initialized)
388 : {
389 0 : initialized = 1;
390 0 : fp = fopen (PKGDATADIR "/errorref.txt", "r");
391 : }
392 0 : if (!fp)
393 : return;
394 0 : rewind (fp);
395 0 : while (fgets (line, sizeof line, fp))
396 : {
397 0 : if (*line == '#')
398 0 : continue;
399 0 : if (*line && line[strlen(line)-1] == '\n')
400 0 : line[strlen(line)-1] = 0;
401 :
402 0 : if (!strncmp (line, "GPG_ERR_", 8))
403 : {
404 0 : if (indesc == 1 && last_was_keyword)
405 0 : continue; /* Skip keywords immediately following a matched
406 : * keyword. */
407 : last_was_keyword = 1;
408 :
409 : indesc = 0;
410 0 : p = strchr (line, ' ');
411 0 : if (!p)
412 0 : continue;
413 0 : *p = 0;
414 0 : if (!strcmp (line, symbol))
415 : {
416 : indesc = 1;
417 0 : continue; /* Skip this line. */
418 : }
419 : }
420 : else
421 : last_was_keyword = 0;
422 0 : if (!indesc)
423 0 : continue;
424 0 : if (indesc == 1 && !*line)
425 0 : continue; /* Skip leading empty lines in a description. */
426 0 : if (indesc == 1)
427 : putchar ('\n'); /* One leading empty line. */
428 : indesc = 2;
429 0 : if (!*line)
430 : {
431 0 : blanklines++;
432 0 : continue;
433 : }
434 0 : for (; blanklines; blanklines--)
435 : putchar ('\n');
436 0 : printf ("%s\n", line);
437 : }
438 : putchar ('\n'); /* One trailing blank line. */
439 : }
440 :
441 :
442 :
443 :
444 :
445 : static int
446 0 : show_usage (const char *name)
447 : {
448 0 : if (name)
449 : {
450 0 : fprintf (stderr, _("Usage: %s GPG-ERROR [...]\n"),
451 0 : strrchr (name,'/')? (strrchr (name, '/')+1): name);
452 0 : exit (1);
453 : }
454 :
455 0 : fputs ("gpg-error (" PACKAGE_NAME ") " PACKAGE_VERSION "\n", stdout);
456 0 : fputs ("Options:\n"
457 : " --version Print version\n"
458 : " --lib-version Print library version\n"
459 : " --help Print this help\n"
460 : " --list Print all error codes\n"
461 : " --defines Print all error codes as #define lines\n"
462 : " --desc Print with error description\n"
463 : , stdout);
464 0 : exit (0);
465 : }
466 :
467 :
468 :
469 : int
470 0 : main (int argc, char *argv[])
471 : {
472 0 : const char *pgmname = argv[0];
473 : int last_argc = -1;
474 : int i;
475 : int listmode = 0;
476 : int desc = 0;
477 : const char *source_sym;
478 : const char *error_sym;
479 : gpg_error_t err;
480 :
481 0 : gpgrt_init ();
482 0 : i18n_init ();
483 :
484 :
485 0 : if (argc)
486 : {
487 0 : argc--; argv++;
488 : }
489 0 : while (argc && last_argc != argc )
490 : {
491 : last_argc = argc;
492 0 : if (!strcmp (*argv, "--"))
493 : {
494 0 : argc--; argv++;
495 0 : break;
496 : }
497 0 : else if (!strcmp (*argv, "--version"))
498 : {
499 0 : fputs ("gpg-error (" PACKAGE_NAME ") " PACKAGE_VERSION "\n", stdout);
500 0 : exit (0);
501 : }
502 0 : else if (!strcmp (*argv, "--help"))
503 : {
504 0 : show_usage (NULL);
505 : }
506 0 : else if (!strcmp (*argv, "--lib-version"))
507 : {
508 : argc--; argv++;
509 0 : printf ("Version from header: %s (0x%06x)\n",
510 : GPG_ERROR_VERSION, GPG_ERROR_VERSION_NUMBER);
511 0 : printf ("Version from binary: %s\n", gpg_error_check_version (NULL));
512 0 : printf ("Copyright blurb ...:%s\n",
513 : gpg_error_check_version ("\x01\x01"));
514 0 : exit (0);
515 : }
516 0 : else if (!strcmp (*argv, "--list"))
517 : {
518 : listmode = 1;
519 0 : argc--; argv++;
520 : }
521 0 : else if (!strcmp (*argv, "--defines"))
522 : {
523 : listmode = 2;
524 0 : argc--; argv++;
525 : }
526 0 : else if (!strcmp (*argv, "--desc"))
527 : {
528 : desc = 1;
529 0 : argc--; argv++;
530 : }
531 0 : else if (!strncmp (*argv, "--", 2))
532 0 : show_usage (pgmname);
533 : }
534 :
535 0 : if ((argc && listmode) || (!argc && !listmode))
536 0 : show_usage (pgmname);
537 :
538 :
539 0 : if (listmode == 1)
540 : {
541 0 : for (i=0; i < GPG_ERR_SOURCE_DIM; i++)
542 : {
543 : /* We use error code 1 because gpg_err_make requires a
544 : non-zero error code. */
545 0 : err = gpg_err_make (i, 1);
546 0 : err -= 1;
547 0 : source_sym = gpg_strsource_sym (err);
548 0 : if (source_sym)
549 : {
550 0 : printf ("%u = (%u, -) = (%s, -) = (%s, -)\n",
551 : err, gpg_err_source (err),
552 : source_sym, gpg_strsource (err));
553 0 : if (desc)
554 0 : print_desc (source_sym);
555 : }
556 : }
557 0 : for (i=0; i < GPG_ERR_CODE_DIM; i++)
558 : {
559 0 : err = gpg_err_make (GPG_ERR_SOURCE_UNKNOWN, i);
560 0 : error_sym = gpg_strerror_sym (err);
561 0 : if (error_sym)
562 : {
563 0 : printf ("%u = (-, %u) = (-, %s) = (-, %s)\n",
564 : err, gpg_err_code (err),
565 : error_sym, gpg_strerror (err));
566 0 : if (desc)
567 0 : print_desc (error_sym);
568 : }
569 : }
570 : }
571 0 : else if (listmode == 2)
572 : {
573 : int n, nmax;
574 :
575 0 : for (i=0, nmax=0; i < GPG_ERR_SOURCE_DIM; i++)
576 : {
577 0 : err = gpg_err_make (i, 1);
578 0 : source_sym = gpg_strsource_sym (err);
579 0 : if (source_sym)
580 : {
581 0 : n = strlen (source_sym);
582 0 : if (n > nmax)
583 : nmax = n;
584 : }
585 : }
586 0 : for (i=0; i < GPG_ERR_SOURCE_DIM; i++)
587 : {
588 0 : err = gpg_err_make (i, 1);
589 0 : source_sym = gpg_strsource_sym (err);
590 0 : if (source_sym)
591 0 : printf ("#define %-*s %3u\n", nmax,source_sym,gpg_err_source (err));
592 : }
593 :
594 :
595 0 : for (i=0, nmax = 0; i < GPG_ERR_CODE_DIM; i++)
596 : {
597 0 : err = gpg_err_make (GPG_ERR_SOURCE_UNKNOWN, i);
598 0 : error_sym = gpg_strerror_sym (err);
599 0 : if (error_sym)
600 : {
601 0 : n = strlen (error_sym);
602 0 : if (n > nmax)
603 : nmax = n;
604 : }
605 : }
606 0 : for (i=0; i < GPG_ERR_CODE_DIM; i++)
607 : {
608 0 : err = gpg_err_make (GPG_ERR_SOURCE_UNKNOWN, i);
609 0 : error_sym = gpg_strerror_sym (err);
610 0 : if (error_sym)
611 0 : printf ("#define %-*s %5u\n", nmax, error_sym, gpg_err_code (err));
612 : }
613 : }
614 : else /* Standard mode. */
615 : {
616 0 : for (i=0; i < argc; i++)
617 : {
618 0 : if (get_err_from_number (argv[i], &err)
619 0 : || get_err_from_symbol (argv[i], &err)
620 0 : || get_err_from_str (argv[i], &err))
621 : {
622 0 : source_sym = gpg_strsource_sym (err);
623 0 : error_sym = gpg_strerror_sym (err);
624 :
625 0 : printf ("%u = (%u, %u) = (%s, %s) = (%s, %s)\n",
626 : err, gpg_err_source (err), gpg_err_code (err),
627 : source_sym ? source_sym : "-", error_sym ? error_sym:"-",
628 : gpg_strsource (err), gpg_strerror (err));
629 0 : if (desc)
630 0 : print_desc (error_sym);
631 : }
632 : else
633 0 : fprintf (stderr, _("%s: warning: could not recognize %s\n"),
634 : argv[0], argv[i]);
635 : }
636 : }
637 :
638 0 : exit (0);
639 : }
|