Line data Source code
1 : /* init.c - Initialize the GnuPG error library.
2 : Copyright (C) 2005, 2010 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 this program; if not, see <https://www.gnu.org/licenses/>.
18 : */
19 :
20 : #if HAVE_CONFIG_H
21 : #include <config.h>
22 : #endif
23 :
24 : #include <stdlib.h>
25 : #include <stdio.h>
26 : #include <string.h>
27 : #include <errno.h>
28 :
29 : #include "gpgrt-int.h"
30 : #include "gettext.h"
31 : #include "init.h"
32 :
33 : #ifdef HAVE_W32CE_SYSTEM
34 : # include "mkw32errmap.map.c" /* Generated map_w32codes () */
35 : # ifndef TLS_OUT_OF_INDEXES
36 : # define TLS_OUT_OF_INDEXES 0xFFFFFFFF
37 : # endif
38 : # ifndef __MINGW32CE__
39 : # /* Replace the Mingw32CE provided abort function. */
40 : # define abort() do { TerminateProcess (GetCurrentProcess(), 8); } while (0)
41 : # endif
42 : #endif
43 :
44 :
45 : /* Locale directory support. */
46 :
47 : #if HAVE_W32_SYSTEM
48 :
49 : #include <windows.h>
50 :
51 : static int tls_index = TLS_OUT_OF_INDEXES; /* Index for the TLS functions. */
52 :
53 : static char *get_locale_dir (void);
54 : static void drop_locale_dir (char *locale_dir);
55 :
56 : #else /*!HAVE_W32_SYSTEM*/
57 :
58 : #define get_locale_dir() LOCALEDIR
59 : #define drop_locale_dir(dir)
60 :
61 : #endif /*!HAVE_W32_SYSTEM*/
62 :
63 :
64 : /* The realloc function as set by gpgrt_set_alloc_func. */
65 : static void *(*custom_realloc)(void *a, size_t n);
66 :
67 :
68 :
69 : static void
70 : real_init (void)
71 : {
72 : #ifdef ENABLE_NLS
73 : char *locale_dir;
74 :
75 : /* We only have to bind our locale directory to our text domain. */
76 : locale_dir = get_locale_dir ();
77 : if (locale_dir)
78 : {
79 7 : bindtextdomain (PACKAGE, locale_dir);
80 : drop_locale_dir (locale_dir);
81 : }
82 : #endif
83 7 : _gpgrt_estream_init ();
84 : }
85 :
86 : /* Initialize the library. This function should be run early. */
87 : gpg_error_t
88 7 : _gpg_err_init (void)
89 : {
90 : #ifdef HAVE_W32_SYSTEM
91 : # ifdef DLL_EXPORT
92 : /* We always have a constructor and thus this function is called
93 : automatically. Due to the way the C init code of mingw works,
94 : the constructors are called before our DllMain function is
95 : called. The problem with that is that the TLS has not been setup
96 : and w32-gettext.c requires TLS. To solve this we do nothing here
97 : but call the actual init code from our DllMain. */
98 : # else /*!DLL_EXPORT*/
99 : /* Note that if the TLS is actually used, we can't release the TLS
100 : as there is no way to know when a thread terminates (i.e. no
101 : thread-specific-atexit). You are really better off to use the
102 : DLL! */
103 : if (tls_index == TLS_OUT_OF_INDEXES)
104 : {
105 : tls_index = TlsAlloc ();
106 : if (tls_index == TLS_OUT_OF_INDEXES)
107 : {
108 : /* No way to continue - commit suicide. */
109 : abort ();
110 : }
111 : _gpg_w32__init_gettext_module ();
112 : real_init ();
113 : }
114 : # endif /*!DLL_EXPORT*/
115 : #else
116 : real_init ();
117 : #endif
118 7 : return 0;
119 : }
120 :
121 :
122 : /* Deinitialize libgpg-error. This function is only used in special
123 : circumstances. No gpg-error function should be used after this
124 : function has been called. A value of 0 passed for MODE
125 : deinitializes the entire libgpg-error, a value of 1 releases
126 : resources allocated for the current thread and only that thread may
127 : not anymore access libgpg-error after such a call. Under Windows
128 : this function may be called from the DllMain function of a DLL
129 : which statically links to libgpg-error. */
130 : void
131 0 : _gpg_err_deinit (int mode)
132 : {
133 : #if defined (HAVE_W32_SYSTEM) && !defined(DLL_EXPORT)
134 : struct tls_space_s *tls;
135 :
136 : tls = TlsGetValue (tls_index);
137 : if (tls)
138 : {
139 : TlsSetValue (tls_index, NULL);
140 : LocalFree (tls);
141 : }
142 :
143 : if (mode == 0)
144 : {
145 : TlsFree (tls_index);
146 : tls_index = TLS_OUT_OF_INDEXES;
147 : }
148 : #else
149 : (void)mode;
150 : #endif
151 0 : }
152 :
153 :
154 :
155 :
156 : /* Register F as allocation function. This function is used for all
157 : APIs which return an allocated buffer. F needs to have standard
158 : realloc semantics. It should be called as early as possible and
159 : not changed later. */
160 : void
161 0 : _gpgrt_set_alloc_func (void *(*f)(void *a, size_t n))
162 : {
163 0 : custom_realloc = f;
164 0 : }
165 :
166 :
167 : /* The realloc to be used for data returned by the public API. */
168 : void *
169 501 : _gpgrt_realloc (void *a, size_t n)
170 : {
171 501 : if (custom_realloc)
172 0 : return custom_realloc (a, n);
173 :
174 501 : if (!n)
175 : {
176 171 : free (a);
177 171 : return NULL;
178 : }
179 :
180 330 : if (!a)
181 330 : return malloc (n);
182 :
183 0 : return realloc (a, n);
184 : }
185 :
186 :
187 : /* The malloc to be used for data returned by the public API. */
188 : void *
189 24 : _gpgrt_malloc (size_t n)
190 : {
191 24 : if (!n)
192 0 : n++;
193 24 : return _gpgrt_realloc (NULL, n);
194 : }
195 :
196 :
197 : /* The free to be used for data returned by the public API. */
198 : void
199 171 : _gpgrt_free (void *a)
200 : {
201 171 : _gpgrt_realloc (a, 0);
202 171 : }
203 :
204 :
205 : void
206 1 : _gpg_err_set_errno (int err)
207 : {
208 : #ifdef HAVE_W32CE_SYSTEM
209 : SetLastError (err);
210 : #else /*!HAVE_W32CE_SYSTEM*/
211 1 : errno = err;
212 : #endif /*!HAVE_W32CE_SYSTEM*/
213 1 : }
214 :
215 :
216 :
217 : /* Internal tracing functions. Except for TARCE_FP we use flockfile
218 : * and funlockfile to protect their use. */
219 : static FILE *trace_fp;
220 : static int trace_save_errno;
221 : static int trace_with_errno;
222 : static const char *trace_arg_module;
223 : static const char *trace_arg_file;
224 : static int trace_arg_line;
225 : static int trace_missing_lf;
226 : static int trace_prefix_done;
227 :
228 : void
229 0 : _gpgrt_internal_trace_begin (const char *module, const char *file, int line,
230 : int with_errno)
231 : {
232 0 : int save_errno = errno;
233 :
234 0 : if (!trace_fp)
235 : {
236 : FILE *fp;
237 0 : const char *s = getenv ("GPGRT_TRACE_FILE");
238 :
239 0 : if (!s || !(fp = fopen (s, "wb")))
240 0 : fp = stderr;
241 0 : trace_fp = fp;
242 : }
243 :
244 : #ifdef HAVE_FLOCKFILE
245 0 : flockfile (trace_fp);
246 : #endif
247 0 : trace_save_errno = save_errno;
248 0 : trace_with_errno = with_errno;
249 0 : trace_arg_module = module;
250 0 : trace_arg_file = file;
251 0 : trace_arg_line = line;
252 0 : trace_missing_lf = 0;
253 0 : trace_prefix_done = 0;
254 0 : }
255 :
256 : static void
257 0 : print_internal_trace_prefix (void)
258 : {
259 0 : if (!trace_prefix_done)
260 : {
261 0 : trace_prefix_done = 1;
262 0 : fprintf (trace_fp, "%s:%s:%d: ",
263 : trace_arg_module,/* npth_is_protected ()?"":"^",*/
264 : trace_arg_file, trace_arg_line);
265 : }
266 0 : }
267 :
268 : static void
269 0 : do_internal_trace (const char *format, va_list arg_ptr)
270 : {
271 0 : print_internal_trace_prefix ();
272 0 : vfprintf (trace_fp, format, arg_ptr);
273 0 : if (trace_with_errno)
274 0 : fprintf (trace_fp, " errno=%s", strerror (trace_save_errno));
275 0 : if (*format && format[strlen(format)-1] != '\n')
276 0 : fputc ('\n', trace_fp);
277 0 : }
278 :
279 : void
280 0 : _gpgrt_internal_trace_printf (const char *format, ...)
281 : {
282 : va_list arg_ptr;
283 :
284 0 : print_internal_trace_prefix ();
285 0 : va_start (arg_ptr, format) ;
286 0 : vfprintf (trace_fp, format, arg_ptr);
287 0 : va_end (arg_ptr);
288 0 : trace_missing_lf = (*format && format[strlen(format)-1] != '\n');
289 0 : }
290 :
291 :
292 : void
293 0 : _gpgrt_internal_trace (const char *format, ...)
294 : {
295 : va_list arg_ptr;
296 :
297 0 : va_start (arg_ptr, format) ;
298 0 : do_internal_trace (format, arg_ptr);
299 0 : va_end (arg_ptr);
300 0 : }
301 :
302 :
303 : void
304 0 : _gpgrt_internal_trace_end (void)
305 : {
306 0 : int save_errno = trace_save_errno;
307 :
308 0 : if (trace_missing_lf)
309 0 : fputc ('\n', trace_fp);
310 : #ifdef HAVE_FLOCKFILE
311 0 : funlockfile (trace_fp);
312 : #endif
313 0 : errno = save_errno;
314 0 : }
315 :
316 :
317 :
318 : #ifdef HAVE_W32_SYSTEM
319 : /*****************************************
320 : ******** Below is only Windows code. ****
321 : *****************************************/
322 :
323 : static char *
324 : get_locale_dir (void)
325 : {
326 : static wchar_t moddir[MAX_PATH+5];
327 : char *result, *p;
328 : int nbytes;
329 :
330 : if (!GetModuleFileNameW (NULL, moddir, MAX_PATH))
331 : *moddir = 0;
332 :
333 : #define SLDIR "\\share\\locale"
334 : if (*moddir)
335 : {
336 : nbytes = WideCharToMultiByte (CP_UTF8, 0, moddir, -1, NULL, 0, NULL, NULL);
337 : if (nbytes < 0)
338 : return NULL;
339 :
340 : result = malloc (nbytes + strlen (SLDIR) + 1);
341 : if (result)
342 : {
343 : nbytes = WideCharToMultiByte (CP_UTF8, 0, moddir, -1,
344 : result, nbytes, NULL, NULL);
345 : if (nbytes < 0)
346 : {
347 : free (result);
348 : result = NULL;
349 : }
350 : else
351 : {
352 : p = strrchr (result, '\\');
353 : if (p)
354 : *p = 0;
355 : /* If we are installed below "bin" strip that part and
356 : use the top directory instead.
357 :
358 : Background: Under Windows we don't install GnuPG
359 : below bin/ but in the top directory with only share/,
360 : lib/, and etc/ below it. One of the reasons is to
361 : keep the the length of the filenames at bay so not to
362 : increase the limited length of the PATH envvar.
363 : Another and more important reason, however, is that
364 : the very first GPG versions on W32 were installed
365 : into a flat directory structure and for best
366 : compatibility with these versions we didn't changed
367 : that later. For WindowsCE we can right away install
368 : it under bin, though. The hack with detection of the
369 : bin directory part allows us to eventually migrate to
370 : such a directory layout under plain Windows without
371 : the need to change libgpg-error. */
372 : p = strrchr (result, '\\');
373 : if (p && !strcmp (p+1, "bin"))
374 : *p = 0;
375 : /* Append the static part. */
376 : strcat (result, SLDIR);
377 : }
378 : }
379 : }
380 : else /* Use the old default value. */
381 : {
382 : result = malloc (10 + strlen (SLDIR) + 1);
383 : if (result)
384 : {
385 : strcpy (result, "c:\\gnupg");
386 : strcat (result, SLDIR);
387 : }
388 : }
389 : #undef SLDIR
390 : return result;
391 : }
392 :
393 :
394 : static void
395 : drop_locale_dir (char *locale_dir)
396 : {
397 : free (locale_dir);
398 : }
399 :
400 :
401 : /* Return the tls object. This function is guaranteed to return a
402 : valid non-NULL object. */
403 : struct tls_space_s *
404 : get_tls (void)
405 : {
406 : struct tls_space_s *tls;
407 :
408 : tls = TlsGetValue (tls_index);
409 : if (!tls)
410 : {
411 : /* Called by a thread which existed before this DLL was loaded.
412 : Allocate the space. */
413 : tls = LocalAlloc (LPTR, sizeof *tls);
414 : if (!tls)
415 : {
416 : /* No way to continue - commit suicide. */
417 : abort ();
418 : }
419 : tls->gt_use_utf8 = 0;
420 : TlsSetValue (tls_index, tls);
421 : }
422 :
423 : return tls;
424 : }
425 :
426 :
427 : /* Return the value of the ERRNO variable. This needs to be a
428 : function so that we can have a per-thread ERRNO. This is used only
429 : on WindowsCE because that OS misses an errno. */
430 : #ifdef HAVE_W32CE_SYSTEM
431 : int
432 : _gpg_w32ce_get_errno (void)
433 : {
434 : return map_w32codes ( GetLastError () );
435 : }
436 : #endif /*HAVE_W32CE_SYSTEM*/
437 :
438 :
439 : /* Replacement strerror function for WindowsCE. */
440 : #ifdef HAVE_W32CE_SYSTEM
441 : char *
442 : _gpg_w32ce_strerror (int err)
443 : {
444 : struct tls_space_s *tls = get_tls ();
445 : wchar_t tmpbuf[STRBUFFER_SIZE];
446 : int n;
447 :
448 : if (err == -1)
449 : err = _gpg_w32ce_get_errno ();
450 :
451 : /* Note: On a German HTC Touch Pro2 device I also tried
452 : LOCALE_USER_DEFAULT and LOCALE_SYSTEM_DEFAULT - both returned
453 : English messages. */
454 : if (FormatMessageW (FORMAT_MESSAGE_FROM_SYSTEM, NULL, err,
455 : MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
456 : tmpbuf, STRBUFFER_SIZE -1,
457 : NULL))
458 : {
459 : n = WideCharToMultiByte (CP_UTF8, 0, tmpbuf, -1,
460 : tls->strerror_buffer,
461 : sizeof tls->strerror_buffer -1,
462 : NULL, NULL);
463 : }
464 : else
465 : n = -1;
466 :
467 : if (n < 0)
468 : snprintf (tls->strerror_buffer, sizeof tls->strerror_buffer -1,
469 : "[w32err=%d]", err);
470 : return tls->strerror_buffer;
471 : }
472 : #endif /*HAVE_W32CE_SYSTEM*/
473 :
474 :
475 : /* Entry point called by the DLL loader. */
476 : #ifdef DLL_EXPORT
477 : int WINAPI
478 : DllMain (HINSTANCE hinst, DWORD reason, LPVOID reserved)
479 : {
480 : struct tls_space_s *tls;
481 : (void)reserved;
482 : (void)hinst;
483 :
484 : switch (reason)
485 : {
486 : case DLL_PROCESS_ATTACH:
487 : tls_index = TlsAlloc ();
488 : if (tls_index == TLS_OUT_OF_INDEXES)
489 : return FALSE;
490 : #ifndef _GPG_ERR_HAVE_CONSTRUCTOR
491 : /* If we have not constructors (e.g. MSC) we call it here. */
492 : _gpg_w32__init_gettext_module ();
493 : #endif
494 : /* falltru. */
495 : case DLL_THREAD_ATTACH:
496 : tls = LocalAlloc (LPTR, sizeof *tls);
497 : if (!tls)
498 : return FALSE;
499 : tls->gt_use_utf8 = 0;
500 : TlsSetValue (tls_index, tls);
501 : if (reason == DLL_PROCESS_ATTACH)
502 : {
503 : real_init ();
504 : }
505 : break;
506 :
507 : case DLL_THREAD_DETACH:
508 : tls = TlsGetValue (tls_index);
509 : if (tls)
510 : LocalFree (tls);
511 : break;
512 :
513 : case DLL_PROCESS_DETACH:
514 : tls = TlsGetValue (tls_index);
515 : if (tls)
516 : LocalFree (tls);
517 : TlsFree (tls_index);
518 : break;
519 :
520 : default:
521 : break;
522 : }
523 :
524 : return TRUE;
525 : }
526 : #endif /*DLL_EXPORT*/
527 :
528 : #endif /*HAVE_W32_SYSTEM*/
|