summary refs log tree commit diff stats
path: root/libotr/libgpg-error-1.42/src/init.c
diff options
context:
space:
mode:
Diffstat (limited to 'libotr/libgpg-error-1.42/src/init.c')
-rw-r--r--libotr/libgpg-error-1.42/src/init.c741
1 files changed, 741 insertions, 0 deletions
diff --git a/libotr/libgpg-error-1.42/src/init.c b/libotr/libgpg-error-1.42/src/init.c
new file mode 100644
index 0000000..6239682
--- /dev/null
+++ b/libotr/libgpg-error-1.42/src/init.c
@@ -0,0 +1,741 @@
+/* init.c - Initialize the GnuPG error library.
+   Copyright (C) 2005, 2010 g10 Code GmbH
+
+   This file is part of libgpg-error.
+
+   libgpg-error is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License
+   as published by the Free Software Foundation; either version 2.1 of
+   the License, or (at your option) any later version.
+
+   libgpg-error is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "gpgrt-int.h"
+#include "gettext.h"
+#include "init.h"
+
+#ifdef HAVE_W32CE_SYSTEM
+# include "mkw32errmap.map.c"  /* Generated map_w32codes () */
+# ifndef TLS_OUT_OF_INDEXES
+#  define TLS_OUT_OF_INDEXES 0xFFFFFFFF
+# endif
+# ifndef __MINGW32CE__
+#  /* Replace the Mingw32CE provided abort function.  */
+#  define abort() do { TerminateProcess (GetCurrentProcess(), 8); } while (0)
+# endif
+#endif
+
+
+/* Locale directory support.  */
+
+#if HAVE_W32_SYSTEM
+
+#include <windows.h>
+
+static int tls_index = TLS_OUT_OF_INDEXES;  /* Index for the TLS functions.  */
+
+static char *get_locale_dir (void);
+static void drop_locale_dir (char *locale_dir);
+
+#else /*!HAVE_W32_SYSTEM*/
+
+#define get_locale_dir() LOCALEDIR
+#define drop_locale_dir(dir)
+
+#endif /*!HAVE_W32_SYSTEM*/
+
+
+/* The list of emergency cleanup functions; see _gpgrt_abort and
+ * _gpgrt_add_emergency_cleanup.  */
+struct emergency_cleanup_item_s;
+typedef struct emergency_cleanup_item_s *emergency_cleanup_item_t;
+struct emergency_cleanup_item_s
+{
+  emergency_cleanup_item_t next;
+  void (*func) (void);
+};
+static emergency_cleanup_item_t emergency_cleanup_list;
+
+
+
+
+/* The realloc function as set by gpgrt_set_alloc_func.  */
+static void *(*custom_realloc)(void *a, size_t n);
+
+
+
+static void
+real_init (void)
+{
+#ifdef ENABLE_NLS
+  char *locale_dir;
+
+  /* We only have to bind our locale directory to our text domain.  */
+  locale_dir = get_locale_dir ();
+  if (locale_dir)
+    {
+      bindtextdomain (PACKAGE, locale_dir);
+      drop_locale_dir (locale_dir);
+    }
+#endif
+  _gpgrt_estream_init ();
+}
+
+/* Initialize the library.  This function should be run early.  */
+gpg_error_t
+_gpg_err_init (void)
+{
+#ifdef HAVE_W32_SYSTEM
+# ifdef DLL_EXPORT
+  /* We always have a constructor and thus this function is called
+     automatically.  Due to the way the C init code of mingw works,
+     the constructors are called before our DllMain function is
+     called.  The problem with that is that the TLS has not been setup
+     and w32-gettext.c requires TLS.  To solve this we do nothing here
+     but call the actual init code from our DllMain.  */
+# else /*!DLL_EXPORT*/
+  /* Note that if the TLS is actually used, we can't release the TLS
+     as there is no way to know when a thread terminates (i.e. no
+     thread-specific-atexit).  You are really better off to use the
+     DLL! */
+  if (tls_index == TLS_OUT_OF_INDEXES)
+    {
+      tls_index = TlsAlloc ();
+      if (tls_index == TLS_OUT_OF_INDEXES)
+        {
+          /* No way to continue - commit suicide.  */
+          _gpgrt_abort ();
+        }
+      _gpg_w32__init_gettext_module ();
+      real_init ();
+    }
+# endif /*!DLL_EXPORT*/
+#else
+  real_init ();
+#endif
+  return 0;
+}
+
+
+/* Deinitialize libgpg-error.  This function is only used in special
+   circumstances.  No gpg-error function should be used after this
+   function has been called.  A value of 0 passed for MODE
+   deinitializes the entire libgpg-error, a value of 1 releases
+   resources allocated for the current thread and only that thread may
+   not anymore access libgpg-error after such a call.  Under Windows
+   this function may be called from the DllMain function of a DLL
+   which statically links to libgpg-error.  */
+void
+_gpg_err_deinit (int mode)
+{
+#if defined (HAVE_W32_SYSTEM) && !defined(DLL_EXPORT)
+  struct tls_space_s *tls;
+
+  tls = TlsGetValue (tls_index);
+  if (tls)
+    {
+      TlsSetValue (tls_index, NULL);
+      LocalFree (tls);
+    }
+
+  if (mode == 0)
+    {
+      TlsFree (tls_index);
+      tls_index = TLS_OUT_OF_INDEXES;
+    }
+#else
+  (void)mode;
+#endif
+}
+
+
+/* Add the emergency cleanup function F to the list of those function.
+ * If the a function with that address has already been registered, it
+ * is not added a second time.  These emergency functions are called
+ * whenever gpgrt_abort is called and at no other place.  Like signal
+ * handles the emergency cleanup functions shall not call any
+ * non-trivial functions and return as soon as possible.  They allow
+ * to cleanup internal states which should not go into a core dumps or
+ * similar.  This is independent of any atexit functions.  We don't
+ * use locks here because in an emergency case we can't use them
+ * anyway.  */
+void
+_gpgrt_add_emergency_cleanup (void (*f)(void))
+{
+  emergency_cleanup_item_t item;
+
+  for (item = emergency_cleanup_list; item; item = item->next)
+    if (item->func == f)
+      return; /* Function has already been registered.  */
+
+  /* We use a standard malloc here.  */
+  item = malloc (sizeof *item);
+  if (item)
+    {
+      item->func = f;
+      item->next = emergency_cleanup_list;
+      emergency_cleanup_list = item;
+    }
+  else
+    _gpgrt_log_fatal ("out of core in gpgrt_add_emergency_cleanup\n");
+}
+
+
+/* Run the emergency handlers.  No locks are used because we are anyway
+ * in an emergency state.  We also can't release any memory.  */
+static void
+run_emergency_cleanup (void)
+{
+  emergency_cleanup_item_t next;
+  void (*f)(void);
+
+  while (emergency_cleanup_list)
+    {
+      next = emergency_cleanup_list->next;
+      f = emergency_cleanup_list->func;
+      emergency_cleanup_list->func = NULL;
+      emergency_cleanup_list = next;
+      if (f)
+        f ();
+    }
+}
+
+
+/* Wrapper around abort to be able to run all emergency cleanup
+ * functions.  */
+void
+_gpgrt_abort (void)
+{
+  run_emergency_cleanup ();
+  abort ();
+}
+
+
+
+/* Register F as allocation function.  This function is used for all
+   APIs which return an allocated buffer.  F needs to have standard
+   realloc semantics.  It should be called as early as possible and
+   not changed later. */
+void
+_gpgrt_set_alloc_func (void *(*f)(void *a, size_t n))
+{
+  custom_realloc = f;
+}
+
+
+/* The realloc to be used for data returned by the public API.  */
+void *
+_gpgrt_realloc (void *a, size_t n)
+{
+  if (custom_realloc)
+    return custom_realloc (a, n);
+
+  if (!n)
+    {
+      free (a);
+      return NULL;
+    }
+
+  if (!a)
+    return malloc (n);
+
+  return realloc (a, n);
+}
+
+
+/* This is safe version of realloc useful for reallocing a calloced
+ * array.  There are two ways to call it:  The first example
+ * reallocates the array A to N elements each of SIZE but does not
+ * clear the newly allocated elements:
+ *
+ *  p = gpgrt_reallocarray (a, n, n, nsize);
+ *
+ * Note that when NOLD is larger than N no cleaning is needed anyway.
+ * The second example reallocates an array of size NOLD to N elements
+ * each of SIZE but clear the newly allocated elements:
+ *
+ *  p = gpgrt_reallocarray (a, nold, n, nsize);
+ *
+ * Note that gpgrt_reallocarray (NULL, 0, n, nsize) is equivalent to
+ * _gpgrt_calloc (n, nsize).
+ *
+ */
+void *
+_gpgrt_reallocarray (void *a, size_t oldnmemb, size_t nmemb, size_t size)
+{
+  size_t oldbytes, bytes;
+  char *p;
+
+  bytes = nmemb * size; /* size_t is unsigned so the behavior on overflow
+                         * is defined. */
+  if (size && bytes / size != nmemb)
+    {
+      _gpg_err_set_errno (ENOMEM);
+      return NULL;
+    }
+
+  p = _gpgrt_realloc (a, bytes);
+  if (p && oldnmemb < nmemb)
+    {
+      /* OLDNMEMBS is lower than NMEMB thus the user asked for a
+         calloc.  Clear all newly allocated members.  */
+      oldbytes = oldnmemb * size;
+      if (size && oldbytes / size != oldnmemb)
+        {
+          xfree (p);
+          _gpg_err_set_errno (ENOMEM);
+          return NULL;
+        }
+      memset (p + oldbytes, 0, bytes - oldbytes);
+    }
+  return p;
+}
+
+
+/* The malloc to be used for data returned by the public API.  */
+void *
+_gpgrt_malloc (size_t n)
+{
+  if (!n)
+    n++;
+  return _gpgrt_realloc (NULL, n);
+}
+
+
+void *
+_gpgrt_calloc (size_t n, size_t m)
+{
+  size_t bytes;
+  void *p;
+
+  bytes = n * m; /* size_t is unsigned so the behavior on overflow is
+                    defined. */
+  if (m && bytes / m != n)
+    {
+      _gpg_err_set_errno (ENOMEM);
+      return NULL;
+    }
+
+  p = _gpgrt_realloc (NULL, bytes);
+  if (p)
+    memset (p, 0, bytes);
+  return p;
+}
+
+
+char *
+_gpgrt_strdup (const char *string)
+{
+  size_t len = strlen (string);
+  char *p;
+
+  p = _gpgrt_realloc (NULL, len + 1);
+  if (p)
+    strcpy (p, string);
+  return p;
+}
+
+
+/* Helper for _gpgrt_strconcat and gpgrt_strconcat.  */
+char *
+_gpgrt_strconcat_core (const char *s1, va_list arg_ptr)
+{
+  const char *argv[48];
+  size_t argc;
+  size_t needed;
+  char *buffer, *p;
+
+  argc = 0;
+  argv[argc++] = s1;
+  needed = strlen (s1);
+  while (((argv[argc] = va_arg (arg_ptr, const char *))))
+    {
+      needed += strlen (argv[argc]);
+      if (argc >= DIM (argv)-1)
+        {
+          _gpg_err_set_errno (EINVAL);
+          return NULL;
+        }
+      argc++;
+    }
+  needed++;
+  buffer = _gpgrt_malloc (needed);
+  if (buffer)
+    {
+      for (p = buffer, argc=0; argv[argc]; argc++)
+        p = stpcpy (p, argv[argc]);
+    }
+  return buffer;
+}
+
+
+char *
+_gpgrt_strconcat (const char *s1, ...)
+{
+  va_list arg_ptr;
+  char *result;
+
+  if (!s1)
+    result = _gpgrt_strdup ("");
+  else
+    {
+      va_start (arg_ptr, s1);
+      result = _gpgrt_strconcat_core (s1, arg_ptr);
+      va_end (arg_ptr);
+    }
+  return result;
+}
+
+
+/* The free to be used for data returned by the public API.  */
+void
+_gpgrt_free (void *a)
+{
+  _gpgrt_realloc (a, 0);
+}
+
+
+void
+_gpg_err_set_errno (int err)
+{
+#ifdef HAVE_W32CE_SYSTEM
+  SetLastError (err);
+#else /*!HAVE_W32CE_SYSTEM*/
+  errno = err;
+#endif /*!HAVE_W32CE_SYSTEM*/
+}
+
+
+
+/* Internal tracing functions.  Except for TRACE_FP we use flockfile
+ * and funlockfile to protect their use.
+ *
+ * Warning: Take care with the trace functions - they may not use any
+ * of our services, in particular not the syscall clamp mechanism for
+ * reasons explained in w32-stream.c:create_reader.  */
+static FILE *trace_fp;
+static int trace_save_errno;
+static int trace_with_errno;
+static const char *trace_arg_module;
+static const char *trace_arg_file;
+static int trace_arg_line;
+static int trace_missing_lf;
+static int trace_prefix_done;
+
+void
+_gpgrt_internal_trace_begin (const char *module, const char *file, int line,
+                             int with_errno)
+{
+  int save_errno = errno;
+
+  if (!trace_fp)
+    {
+      FILE *fp;
+      const char *s = getenv ("GPGRT_TRACE_FILE");
+
+      if (!s || !(fp = fopen (s, "wb")))
+        fp = stderr;
+      trace_fp = fp;
+    }
+
+#ifdef HAVE_FLOCKFILE
+  flockfile (trace_fp);
+#endif
+  trace_save_errno = save_errno;
+  trace_with_errno = with_errno;
+  trace_arg_module = module;
+  trace_arg_file = file;
+  trace_arg_line = line;
+  trace_missing_lf = 0;
+  trace_prefix_done = 0;
+}
+
+static void
+print_internal_trace_prefix (void)
+{
+  if (!trace_prefix_done)
+    {
+      trace_prefix_done = 1;
+      fprintf (trace_fp, "%s:%s:%d: ",
+               trace_arg_module,/* npth_is_protected ()?"":"^",*/
+               trace_arg_file, trace_arg_line);
+    }
+}
+
+static void
+do_internal_trace (const char *format, va_list arg_ptr)
+{
+  print_internal_trace_prefix ();
+  vfprintf (trace_fp, format, arg_ptr);
+  if (trace_with_errno)
+    fprintf (trace_fp, " errno=%s", strerror (trace_save_errno));
+  if (*format && format[strlen(format)-1] != '\n')
+    fputc ('\n', trace_fp);
+}
+
+void
+_gpgrt_internal_trace_printf (const char *format, ...)
+{
+  va_list arg_ptr;
+
+  print_internal_trace_prefix ();
+  va_start (arg_ptr, format) ;
+  vfprintf (trace_fp, format, arg_ptr);
+  va_end (arg_ptr);
+  trace_missing_lf = (*format && format[strlen(format)-1] != '\n');
+}
+
+
+void
+_gpgrt_internal_trace (const char *format, ...)
+{
+  va_list arg_ptr;
+
+  va_start (arg_ptr, format) ;
+  do_internal_trace (format, arg_ptr);
+  va_end (arg_ptr);
+}
+
+
+void
+_gpgrt_internal_trace_end (void)
+{
+  int save_errno = trace_save_errno;
+
+  if (trace_missing_lf)
+    fputc ('\n', trace_fp);
+#ifdef HAVE_FLOCKFILE
+  funlockfile (trace_fp);
+#endif
+  errno = save_errno;
+}
+
+
+
+#ifdef HAVE_W32_SYSTEM
+/*****************************************
+ ******** Below is only Windows code. ****
+ *****************************************/
+
+static char *
+get_locale_dir (void)
+{
+  static wchar_t moddir[MAX_PATH+5];
+  char *result, *p;
+  int nbytes;
+
+  if (!GetModuleFileNameW (NULL, moddir, MAX_PATH))
+    *moddir = 0;
+
+#define SLDIR "\\share\\locale"
+  if (*moddir)
+    {
+      nbytes = WideCharToMultiByte (CP_UTF8, 0, moddir, -1, NULL, 0, NULL, NULL);
+      if (nbytes < 0)
+        return NULL;
+
+      result = malloc (nbytes + strlen (SLDIR) + 1);
+      if (result)
+        {
+          nbytes = WideCharToMultiByte (CP_UTF8, 0, moddir, -1,
+                                        result, nbytes, NULL, NULL);
+          if (nbytes < 0)
+            {
+              free (result);
+              result = NULL;
+            }
+          else
+            {
+              p = strrchr (result, '\\');
+              if (p)
+                *p = 0;
+              /* If we are installed below "bin" strip that part and
+                 use the top directory instead.
+
+                 Background: Under Windows we don't install GnuPG
+                 below bin/ but in the top directory with only share/,
+                 lib/, and etc/ below it.  One of the reasons is to
+                 keep the the length of the filenames at bay so not to
+                 increase the limited length of the PATH envvar.
+                 Another and more important reason, however, is that
+                 the very first GPG versions on W32 were installed
+                 into a flat directory structure and for best
+                 compatibility with these versions we didn't changed
+                 that later.  For WindowsCE we can right away install
+                 it under bin, though.  The hack with detection of the
+                 bin directory part allows us to eventually migrate to
+                 such a directory layout under plain Windows without
+                 the need to change libgpg-error.  */
+              p = strrchr (result, '\\');
+              if (p && !strcmp (p+1, "bin"))
+                *p = 0;
+              /* Append the static part.  */
+              strcat (result, SLDIR);
+            }
+        }
+    }
+  else /* Use the old default value.  */
+    {
+      result = malloc (10 + strlen (SLDIR) + 1);
+      if (result)
+        {
+          strcpy (result, "c:\\gnupg");
+          strcat (result, SLDIR);
+        }
+    }
+#undef SLDIR
+  return result;
+}
+
+
+static void
+drop_locale_dir (char *locale_dir)
+{
+  free (locale_dir);
+}
+
+
+/* Return the tls object.  This function is guaranteed to return a
+   valid non-NULL object.  */
+struct tls_space_s *
+get_tls (void)
+{
+  struct tls_space_s *tls;
+
+  tls = TlsGetValue (tls_index);
+  if (!tls)
+    {
+      /* Called by a thread which existed before this DLL was loaded.
+         Allocate the space.  */
+      tls = LocalAlloc (LPTR, sizeof *tls);
+      if (!tls)
+        {
+          /* No way to continue - commit suicide.  */
+          _gpgrt_abort ();
+        }
+      tls->gt_use_utf8 = 0;
+      TlsSetValue (tls_index, tls);
+    }
+
+  return tls;
+}
+
+
+/* Return the value of the ERRNO variable.  This needs to be a
+   function so that we can have a per-thread ERRNO.  This is used only
+   on WindowsCE because that OS misses an errno.   */
+#ifdef HAVE_W32CE_SYSTEM
+int
+_gpg_w32ce_get_errno (void)
+{
+  return map_w32codes ( GetLastError () );
+}
+#endif /*HAVE_W32CE_SYSTEM*/
+
+
+/* Replacement strerror function for WindowsCE.  */
+#ifdef HAVE_W32CE_SYSTEM
+char *
+_gpg_w32ce_strerror (int err)
+{
+  struct tls_space_s *tls = get_tls ();
+  wchar_t tmpbuf[STRBUFFER_SIZE];
+  int n;
+
+  if (err == -1)
+    err = _gpg_w32ce_get_errno ();
+
+  /* Note: On a German HTC Touch Pro2 device I also tried
+     LOCALE_USER_DEFAULT and LOCALE_SYSTEM_DEFAULT - both returned
+     English messages.  */
+  if (FormatMessageW (FORMAT_MESSAGE_FROM_SYSTEM, NULL, err,
+                      MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
+                      tmpbuf, STRBUFFER_SIZE -1,
+                      NULL))
+    {
+      n = WideCharToMultiByte (CP_UTF8, 0, tmpbuf, -1,
+                               tls->strerror_buffer,
+                               sizeof tls->strerror_buffer -1,
+                               NULL, NULL);
+    }
+  else
+    n = -1;
+
+  if (n < 0)
+    snprintf (tls->strerror_buffer, sizeof tls->strerror_buffer -1,
+              "[w32err=%d]", err);
+  return tls->strerror_buffer;
+}
+#endif /*HAVE_W32CE_SYSTEM*/
+
+
+/* Entry point called by the DLL loader.  */
+#ifdef DLL_EXPORT
+int WINAPI
+DllMain (HINSTANCE hinst, DWORD reason, LPVOID reserved)
+{
+  struct tls_space_s *tls;
+  (void)reserved;
+  (void)hinst;
+
+  switch (reason)
+    {
+    case DLL_PROCESS_ATTACH:
+      tls_index = TlsAlloc ();
+      if (tls_index == TLS_OUT_OF_INDEXES)
+        return FALSE;
+#ifndef _GPG_ERR_HAVE_CONSTRUCTOR
+      /* If we have not constructors (e.g. MSC) we call it here.  */
+      _gpg_w32__init_gettext_module ();
+#endif
+      /* fallthru.  */
+    case DLL_THREAD_ATTACH:
+      tls = LocalAlloc (LPTR, sizeof *tls);
+      if (!tls)
+        return FALSE;
+      tls->gt_use_utf8 = 0;
+      TlsSetValue (tls_index, tls);
+      if (reason == DLL_PROCESS_ATTACH)
+        {
+          real_init ();
+        }
+      break;
+
+    case DLL_THREAD_DETACH:
+      tls = TlsGetValue (tls_index);
+      if (tls)
+        LocalFree (tls);
+      break;
+
+    case DLL_PROCESS_DETACH:
+      tls = TlsGetValue (tls_index);
+      if (tls)
+        LocalFree (tls);
+      TlsFree (tls_index);
+      break;
+
+    default:
+      break;
+    }
+
+  return TRUE;
+}
+#endif /*DLL_EXPORT*/
+
+#endif /*HAVE_W32_SYSTEM*/