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 0 : bindtextdomain (PACKAGE, locale_dir);
80 : drop_locale_dir (locale_dir);
81 : }
82 : #endif
83 0 : _gpgrt_es_init ();
84 : }
85 :
86 : /* Initialize the library. This function should be run early. */
87 : gpg_error_t
88 0 : _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 0 : 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 0 : _gpgrt_realloc (void *a, size_t n)
170 : {
171 0 : if (custom_realloc)
172 0 : return custom_realloc (a, n);
173 :
174 0 : if (!n)
175 : {
176 0 : free (a);
177 0 : return NULL;
178 : }
179 :
180 0 : if (!a)
181 0 : 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 0 : _gpgrt_malloc (size_t n)
190 : {
191 0 : if (!n)
192 0 : n++;
193 0 : return _gpgrt_realloc (NULL, n);
194 : }
195 :
196 :
197 : /* The free to be used for data returned by the public API. */
198 : void
199 0 : _gpgrt_free (void *a)
200 : {
201 0 : _gpgrt_realloc (a, 0);
202 0 : }
203 :
204 :
205 : void
206 0 : _gpg_err_set_errno (int err)
207 : {
208 : #ifdef HAVE_W32CE_SYSTEM
209 : SetLastError (err);
210 : #else /*!HAVE_W32CE_SYSTEM*/
211 0 : errno = err;
212 : #endif /*!HAVE_W32CE_SYSTEM*/
213 0 : }
214 :
215 :
216 :
217 : #ifdef HAVE_W32_SYSTEM
218 : /*****************************************
219 : ******** Below is only Windows code. ****
220 : *****************************************/
221 :
222 : static char *
223 : get_locale_dir (void)
224 : {
225 : static wchar_t moddir[MAX_PATH+5];
226 : char *result, *p;
227 : int nbytes;
228 :
229 : if (!GetModuleFileNameW (NULL, moddir, MAX_PATH))
230 : *moddir = 0;
231 :
232 : #define SLDIR "\\share\\locale"
233 : if (*moddir)
234 : {
235 : nbytes = WideCharToMultiByte (CP_UTF8, 0, moddir, -1, NULL, 0, NULL, NULL);
236 : if (nbytes < 0)
237 : return NULL;
238 :
239 : result = malloc (nbytes + strlen (SLDIR) + 1);
240 : if (result)
241 : {
242 : nbytes = WideCharToMultiByte (CP_UTF8, 0, moddir, -1,
243 : result, nbytes, NULL, NULL);
244 : if (nbytes < 0)
245 : {
246 : free (result);
247 : result = NULL;
248 : }
249 : else
250 : {
251 : p = strrchr (result, '\\');
252 : if (p)
253 : *p = 0;
254 : /* If we are installed below "bin" strip that part and
255 : use the top directory instead.
256 :
257 : Background: Under Windows we don't install GnuPG
258 : below bin/ but in the top directory with only share/,
259 : lib/, and etc/ below it. One of the reasons is to
260 : keep the the length of the filenames at bay so not to
261 : increase the limited length of the PATH envvar.
262 : Another and more important reason, however, is that
263 : the very first GPG versions on W32 were installed
264 : into a flat directory structure and for best
265 : compatibility with these versions we didn't changed
266 : that later. For WindowsCE we can right away install
267 : it under bin, though. The hack with detection of the
268 : bin directory part allows us to eventually migrate to
269 : such a directory layout under plain Windows without
270 : the need to change libgpg-error. */
271 : p = strrchr (result, '\\');
272 : if (p && !strcmp (p+1, "bin"))
273 : *p = 0;
274 : /* Append the static part. */
275 : strcat (result, SLDIR);
276 : }
277 : }
278 : }
279 : else /* Use the old default value. */
280 : {
281 : result = malloc (10 + strlen (SLDIR) + 1);
282 : if (result)
283 : {
284 : strcpy (result, "c:\\gnupg");
285 : strcat (result, SLDIR);
286 : }
287 : }
288 : #undef SLDIR
289 : return result;
290 : }
291 :
292 :
293 : static void
294 : drop_locale_dir (char *locale_dir)
295 : {
296 : free (locale_dir);
297 : }
298 :
299 :
300 : /* Return the tls object. This function is guaranteed to return a
301 : valid non-NULL object. */
302 : struct tls_space_s *
303 : get_tls (void)
304 : {
305 : struct tls_space_s *tls;
306 :
307 : tls = TlsGetValue (tls_index);
308 : if (!tls)
309 : {
310 : /* Called by a thread which existed before this DLL was loaded.
311 : Allocate the space. */
312 : tls = LocalAlloc (LPTR, sizeof *tls);
313 : if (!tls)
314 : {
315 : /* No way to continue - commit suicide. */
316 : abort ();
317 : }
318 : tls->gt_use_utf8 = 0;
319 : TlsSetValue (tls_index, tls);
320 : }
321 :
322 : return tls;
323 : }
324 :
325 :
326 : /* Return the value of the ERRNO variable. This needs to be a
327 : function so that we can have a per-thread ERRNO. This is used only
328 : on WindowsCE because that OS misses an errno. */
329 : #ifdef HAVE_W32CE_SYSTEM
330 : int
331 : _gpg_w32ce_get_errno (void)
332 : {
333 : return map_w32codes ( GetLastError () );
334 : }
335 : #endif /*HAVE_W32CE_SYSTEM*/
336 :
337 :
338 : /* Replacement strerror function for WindowsCE. */
339 : #ifdef HAVE_W32CE_SYSTEM
340 : char *
341 : _gpg_w32ce_strerror (int err)
342 : {
343 : struct tls_space_s *tls = get_tls ();
344 : wchar_t tmpbuf[STRBUFFER_SIZE];
345 : int n;
346 :
347 : if (err == -1)
348 : err = _gpg_w32ce_get_errno ();
349 :
350 : /* Note: On a German HTC Touch Pro2 device I also tried
351 : LOCALE_USER_DEFAULT and LOCALE_SYSTEM_DEFAULT - both returned
352 : English messages. */
353 : if (FormatMessageW (FORMAT_MESSAGE_FROM_SYSTEM, NULL, err,
354 : MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
355 : tmpbuf, STRBUFFER_SIZE -1,
356 : NULL))
357 : {
358 : n = WideCharToMultiByte (CP_UTF8, 0, tmpbuf, -1,
359 : tls->strerror_buffer,
360 : sizeof tls->strerror_buffer -1,
361 : NULL, NULL);
362 : }
363 : else
364 : n = -1;
365 :
366 : if (n < 0)
367 : snprintf (tls->strerror_buffer, sizeof tls->strerror_buffer -1,
368 : "[w32err=%d]", err);
369 : return tls->strerror_buffer;
370 : }
371 : #endif /*HAVE_W32CE_SYSTEM*/
372 :
373 :
374 : /* Entry point called by the DLL loader. */
375 : #ifdef DLL_EXPORT
376 : int WINAPI
377 : DllMain (HINSTANCE hinst, DWORD reason, LPVOID reserved)
378 : {
379 : struct tls_space_s *tls;
380 : (void)reserved;
381 : (void)hinst;
382 :
383 : switch (reason)
384 : {
385 : case DLL_PROCESS_ATTACH:
386 : tls_index = TlsAlloc ();
387 : if (tls_index == TLS_OUT_OF_INDEXES)
388 : return FALSE;
389 : #ifndef _GPG_ERR_HAVE_CONSTRUCTOR
390 : /* If we have not constructors (e.g. MSC) we call it here. */
391 : _gpg_w32__init_gettext_module ();
392 : #endif
393 : /* falltru. */
394 : case DLL_THREAD_ATTACH:
395 : tls = LocalAlloc (LPTR, sizeof *tls);
396 : if (!tls)
397 : return FALSE;
398 : tls->gt_use_utf8 = 0;
399 : TlsSetValue (tls_index, tls);
400 : if (reason == DLL_PROCESS_ATTACH)
401 : {
402 : real_init ();
403 : }
404 : break;
405 :
406 : case DLL_THREAD_DETACH:
407 : tls = TlsGetValue (tls_index);
408 : if (tls)
409 : LocalFree (tls);
410 : break;
411 :
412 : case DLL_PROCESS_DETACH:
413 : tls = TlsGetValue (tls_index);
414 : if (tls)
415 : LocalFree (tls);
416 : TlsFree (tls_index);
417 : break;
418 :
419 : default:
420 : break;
421 : }
422 :
423 : return TRUE;
424 : }
425 : #endif /*DLL_EXPORT*/
426 :
427 : #endif /*HAVE_W32_SYSTEM*/
|