api: New function gcry_get_config.
authorWerner Koch <wk@gnupg.org>
Wed, 21 Jun 2017 07:29:09 +0000 (09:29 +0200)
committerWerner Koch <wk@gnupg.org>
Wed, 21 Jun 2017 07:39:21 +0000 (09:39 +0200)
* src/misc.c (_gcry_log_info_with_dummy_fp): Remove.
* src/global.c (print_config): New arg WHAT.  Remove arg FNC and use
gpgrt_fprintf directly.
(_gcry_get_config): New.
(_gcry_vcontrol) <GCRYCTL_PRINT_CONFIG>: Use _gcry_get_config instead
of print_config.
* src/gcrypt.h.in (gcry_get_config): New.
* src/libgcrypt.def, src/libgcrypt.vers: Add new function.
* src/visibility.c (gcry_get_config): New.
* src/visibility.h: Mark new function.

* tests/version.c (test_get_config): New.
(main): Call new test.

Signed-off-by: Werner Koch <wk@gnupg.org>
NEWS
doc/gcrypt.texi
src/g10lib.h
src/gcrypt.h.in
src/global.c
src/libgcrypt.def
src/libgcrypt.vers
src/misc.c
src/visibility.c
src/visibility.h
tests/version.c

diff --git a/NEWS b/NEWS
index d7e9bd9..c97f425 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -67,6 +67,7 @@ Noteworthy changes in version 1.8.0 (unreleased)  [C21/A1/R_]
  * Interface changes relative to the 1.7.0 release:
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    GCRYCTL_REINIT_SYSCALL_CLAMP    NEW macro.
+   gcry_get_config                 NEW function.
    gcry_md_info                    DEPRECATED.
 
 
index 26dd6c3..cab1318 100644 (file)
@@ -824,7 +824,8 @@ proper random device.
 This command dumps information pertaining to the configuration of the
 library to the given stream.  If NULL is given for @var{stream}, the log
 system is used.  This command may be used before the initialization has
-been finished but not before a @code{gcry_check_version}.
+been finished but not before a @code{gcry_check_version}.  Note that
+the macro @code{estream_t} can be used instead of @code{gpgrt_stream_t}.
 
 @item GCRYCTL_OPERATIONAL_P; Arguments: none
 This command returns true if the library is in an operational state.
@@ -5233,6 +5234,7 @@ wrong.
 * Memory allocation::   Functions related with memory allocation.
 * Context management::  Functions related with context management.
 * Buffer description::  A data type to describe buffers.
+* Config reporting::    How to return Libgcrypt's configuration.
 @end menu
 
 
@@ -5317,6 +5319,27 @@ of this structure are:
   @end table
 @end deftp
 
+@node Config reporting
+@section How to return Libgcrypt's configuration.
+
+Although @code{GCRYCTL_PRINT_CONFIG} can be used to print
+configuration options, it is sometimes necessary to check them in a
+program.  This can be accomplished by using this function:
+
+@deftypefun {char *} gcry_get_config @
+             (@w{int @var{mode}}, @
+             @w{const char *@var{what}})
+
+This function returns a malloced string with colon delimited configure
+options.  With a value of 0 for @var{mode} this string resembles the
+output of @code{GCRYCTL_PRINT_CONFIG}.  However, if @var{what} is not
+NULL, only the line where the first field (e.g. "cpu-arch") matches
+@var{what} is returned.
+
+Other values than 0 for @var{mode} are not defined.  The caller shall
+free the string using @code{gcry_free}.  On error NULL is returned and
+ERRNO is set; if a value for WHAT is unknow ERRNO will be set to 0.
+@end deftypefun
 
 
 @c **********************************************************
index ec8aab5..961b515 100644 (file)
@@ -109,6 +109,8 @@ void _gcry_pre_syscall (void);
 void _gcry_post_syscall (void);
 int _gcry_get_debug_flag (unsigned int mask);
 
+char *_gcry_get_config (int mode, const char *what);
+
 /* Malloc functions and common wrapper macros.  */
 void *_gcry_malloc (size_t n) _GCRY_GCC_ATTR_MALLOC;
 void *_gcry_calloc (size_t n, size_t m) _GCRY_GCC_ATTR_MALLOC;
@@ -163,8 +165,6 @@ void _gcry_log_bug( const char *fmt, ... )   JNLIB_GCC_A_NR_PRINTF(1,2);
 void _gcry_log_fatal( const char *fmt, ... ) JNLIB_GCC_A_NR_PRINTF(1,2);
 void _gcry_log_error( const char *fmt, ... ) JNLIB_GCC_A_PRINTF(1,2);
 void _gcry_log_info( const char *fmt, ... )  JNLIB_GCC_A_PRINTF(1,2);
-int  _gcry_log_info_with_dummy_fp (FILE *fp, const char *fmt, ... )
-                                             JNLIB_GCC_A_PRINTF(2,3);
 void _gcry_log_debug( const char *fmt, ... ) JNLIB_GCC_A_PRINTF(1,2);
 void _gcry_log_printf ( const char *fmt, ... ) JNLIB_GCC_A_PRINTF(1,2);
 void _gcry_log_printhex (const char *text, const void *buffer, size_t length);
@@ -174,6 +174,7 @@ void _gcry_log_printsxp (const char *text, gcry_sexp_t sexp);
 void _gcry_set_log_verbosity( int level );
 int _gcry_log_verbosity( int level );
 
+
 #ifdef JNLIB_GCC_M_FUNCTION
 #define BUG() _gcry_bug( __FILE__ , __LINE__, __FUNCTION__ )
 #define gcry_assert(expr) (LIKELY(expr)? (void)0 \
index 210ea2f..8d20c83 100644 (file)
@@ -1691,6 +1691,7 @@ void gcry_log_debugpnt (const char *text,
                         gcry_mpi_point_t point, gcry_ctx_t ctx);
 void gcry_log_debugsxp (const char *text, gcry_sexp_t sexp);
 
+char *gcry_get_config (int mode, const char *what);
 
 /* Log levels used by the internal logging facility. */
 enum gcry_log_levels
index 0796a94..4e2e274 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003
  *               2004, 2005, 2006, 2008, 2011,
  *               2012  Free Software Foundation, Inc.
- * Copyright (C) 2013, 2014 g10 Code GmbH
+ * Copyright (C) 2013, 2014, 2017 g10 Code GmbH
  *
  * This file is part of Libgcrypt.
  *
@@ -273,91 +273,181 @@ _gcry_check_version (const char *req_version)
 
 
 static void
-print_config ( int (*fnc)(FILE *fp, const char *format, ...), FILE *fp)
+print_config (const char *what, gpgrt_stream_t fp)
 {
-  unsigned int hwfeatures, afeature;
   int i;
   const char *s;
 
-  fnc (fp, "version:%s:%x:%s:%x:\n",
-       VERSION, GCRYPT_VERSION_NUMBER,
-       GPGRT_VERSION, GPGRT_VERSION_NUMBER);
-  fnc (fp, "cc:%d:%s:\n",
+  if (!what || !strcmp (what, "version"))
+    {
+      gpgrt_fprintf (fp, "version:%s:%x:%s:%x:\n",
+                     VERSION, GCRYPT_VERSION_NUMBER,
+                     GPGRT_VERSION, GPGRT_VERSION_NUMBER);
+    }
+  if (!what || !strcmp (what, "cc"))
+    {
+      gpgrt_fprintf (fp, "cc:%d:%s:\n",
 #if GPGRT_VERSION_NUMBER >= 0x011b00 /* 1.27 */
-       GPGRT_GCC_VERSION
+                     GPGRT_GCC_VERSION
 #else
-       _GPG_ERR_GCC_VERSION /* Due to a bug in gpg-error.h.  */
+                     _GPG_ERR_GCC_VERSION /* Due to a bug in gpg-error.h.  */
 #endif
-       ,
+                     ,
 #ifdef __clang__
-       "clang:" __VERSION__
+                     "clang:" __VERSION__
 #elif __GNUC__
-       "gcc:" __VERSION__
+                     "gcc:" __VERSION__
 #else
-       ":"
+                     ":"
 #endif
-       );
+                     );
+    }
 
-  fnc (fp, "ciphers:%s:\n", LIBGCRYPT_CIPHERS);
-  fnc (fp, "pubkeys:%s:\n", LIBGCRYPT_PUBKEY_CIPHERS);
-  fnc (fp, "digests:%s:\n", LIBGCRYPT_DIGESTS);
-  fnc (fp, "rnd-mod:"
+  if (!what || !strcmp (what, "ciphers"))
+    gpgrt_fprintf (fp, "ciphers:%s:\n", LIBGCRYPT_CIPHERS);
+  if (!what || !strcmp (what, "pubkeys"))
+    gpgrt_fprintf (fp, "pubkeys:%s:\n", LIBGCRYPT_PUBKEY_CIPHERS);
+  if (!what || !strcmp (what, "digests"))
+    gpgrt_fprintf (fp, "digests:%s:\n", LIBGCRYPT_DIGESTS);
+
+  if (!what || !strcmp (what, "rnd-mod"))
+    {
+      gpgrt_fprintf (fp, "rnd-mod:"
 #if USE_RNDEGD
-                "egd:"
+                     "egd:"
 #endif
 #if USE_RNDLINUX
-                "linux:"
+                     "linux:"
 #endif
 #if USE_RNDUNIX
-                "unix:"
+                     "unix:"
 #endif
 #if USE_RNDW32
-                "w32:"
+                     "w32:"
 #endif
-       "\n");
-  fnc (fp, "cpu-arch:"
+                     "\n");
+    }
+
+  if (!what || !strcmp (what, "cpu-arch"))
+    {
+      gpgrt_fprintf (fp, "cpu-arch:"
 #if defined(HAVE_CPU_ARCH_X86)
-       "x86"
+                     "x86"
 #elif defined(HAVE_CPU_ARCH_ALPHA)
-       "alpha"
+                     "alpha"
 #elif defined(HAVE_CPU_ARCH_SPARC)
-       "sparc"
+                     "sparc"
 #elif defined(HAVE_CPU_ARCH_MIPS)
-       "mips"
+                     "mips"
 #elif defined(HAVE_CPU_ARCH_M68K)
-       "m68k"
+                     "m68k"
 #elif defined(HAVE_CPU_ARCH_PPC)
-       "ppc"
+                     "ppc"
 #elif defined(HAVE_CPU_ARCH_ARM)
-       "arm"
+                     "arm"
 #endif
-       ":\n");
-  fnc (fp, "mpi-asm:%s:\n", _gcry_mpi_get_hw_config ());
-  hwfeatures = _gcry_get_hw_features ();
-  fnc (fp, "hwflist:");
-  for (i=0; (s = _gcry_enum_hw_features (i, &afeature)); i++)
-    if ((hwfeatures & afeature))
-      fnc (fp, "%s:", s);
-  fnc (fp, "\n");
-  /* We use y/n instead of 1/0 for the simple reason that Emacsen's
-     compile error parser would accidentally flag that line when printed
-     during "make check" as an error.  */
-  fnc (fp, "fips-mode:%c:%c:\n",
-       fips_mode ()? 'y':'n',
-       _gcry_enforced_fips_mode ()? 'y':'n' );
-  /* The currently used RNG type.  */
-  {
-    i = _gcry_get_rng_type (0);
-    switch (i)
-      {
-      case GCRY_RNG_TYPE_STANDARD: s = "standard"; break;
-      case GCRY_RNG_TYPE_FIPS:     s = "fips"; break;
-      case GCRY_RNG_TYPE_SYSTEM:   s = "system"; break;
-      default: BUG ();
-      }
-    fnc (fp, "rng-type:%s:%d:\n", s, i);
-  }
+                     ":\n");
+    }
+
+  if (!what || !strcmp (what, "mpi-asm"))
+    gpgrt_fprintf (fp, "mpi-asm:%s:\n", _gcry_mpi_get_hw_config ());
+
+  if (!what || !strcmp (what, "hwflist"))
+    {
+      unsigned int hwfeatures, afeature;
+
+      hwfeatures = _gcry_get_hw_features ();
+      gpgrt_fprintf (fp, "hwflist:");
+      for (i=0; (s = _gcry_enum_hw_features (i, &afeature)); i++)
+        if ((hwfeatures & afeature))
+          gpgrt_fprintf (fp, "%s:", s);
+      gpgrt_fprintf (fp, "\n");
+    }
+
+  if (!what || !strcmp (what, "fips-mode"))
+    {
+      /* We use y/n instead of 1/0 for the stupid reason that
+       * Emacsen's compile error parser would accidentally flag that
+       * line when printed during "make check" as an error.  */
+      gpgrt_fprintf (fp, "fips-mode:%c:%c:\n",
+                     fips_mode ()? 'y':'n',
+                     _gcry_enforced_fips_mode ()? 'y':'n' );
+    }
+
+  if (!what || !strcmp (what, "rng-type"))
+    {
+      /* The currently used RNG type.  */
+      unsigned int jver;
+      int active;
+
+      i = _gcry_get_rng_type (0);
+      switch (i)
+        {
+        case GCRY_RNG_TYPE_STANDARD: s = "standard"; break;
+        case GCRY_RNG_TYPE_FIPS:     s = "fips"; break;
+        case GCRY_RNG_TYPE_SYSTEM:   s = "system"; break;
+        default: BUG ();
+        }
+      jver = _gcry_rndjent_get_version (&active);
+      gpgrt_fprintf (fp, "rng-type:%s:%d:%u:%d:\n", s, i, jver, active);
+    }
+}
+
+
+/* With a MODE of 0 return a malloced string with configured features.
+ * In that case a WHAT of NULL returns everything in the same way
+ * GCRYCTL_PRINT_CONFIG would do.  With a specific WHAT string only
+ * the requested feature is returned (w/o the trailing LF.  On error
+ * NULL is returned.  */
+char *
+_gcry_get_config (int mode, const char *what)
+{
+  gpgrt_stream_t fp;
+  int save_errno;
+  void *data;
+  char *p;
+
+  if (mode)
+    {
+      gpg_err_set_errno (EINVAL);
+      return NULL;
+    }
+
+  fp = gpgrt_fopenmem (0, "w+b,samethread");
+  if (!fp)
+    return NULL;
+
+  print_config (what, fp);
+  if (gpgrt_ferror (fp))
+    {
+      save_errno = errno;
+      gpgrt_fclose (fp);
+      gpg_err_set_errno (save_errno);
+      return NULL;
+    }
+
+  gpgrt_rewind (fp);
+  if (gpgrt_fclose_snatch (fp, &data, NULL))
+    {
+      save_errno = errno;
+      gpgrt_fclose (fp);
+      gpg_err_set_errno (save_errno);
+      return NULL;
+    }
+
+  if (!data)
+    {
+      /* Nothing was printed (unknown value for WHAT).  This is okay,
+       * so clear ERRNO to indicate this. */
+      gpg_err_set_errno (0);
+      return NULL;
+    }
+
+  /* Strip trailing LF.  */
+  if (what && (p = strchr (data, '\n')))
+    *p = 0;
 
+  return data;
 }
 
 
@@ -549,12 +639,21 @@ _gcry_vcontrol (enum gcry_ctl_cmds cmd, va_list arg_ptr)
       /* This command dumps information pertaining to the
          configuration of libgcrypt to the given stream.  It may be
          used before the initialization has been finished but not
-         before a gcry_version_check. */
+         before a gcry_version_check.  See also gcry_get_config.  */
     case GCRYCTL_PRINT_CONFIG:
       {
         FILE *fp = va_arg (arg_ptr, FILE *);
+        char *tmpstr;
         _gcry_set_preferred_rng_type (0);
-        print_config (fp?fprintf:_gcry_log_info_with_dummy_fp, fp);
+        tmpstr = _gcry_get_config (0, NULL);
+        if (tmpstr)
+          {
+            if (fp)
+              fputs (tmpstr, fp);
+            else
+              log_info ("%s", tmpstr);
+            xfree (tmpstr);
+          }
       }
       break;
 
index 067cb84..c4a9eac 100644 (file)
@@ -282,4 +282,6 @@ EXPORTS
 
       gcry_mpi_ec_decode_point  @246
 
+      gcry_get_config           @247
+
 ;; end of file with public symbols for Windows.
index 785b8ed..1d2d150 100644 (file)
@@ -111,6 +111,8 @@ GCRYPT_1.6 {
     gcry_log_debug;
     gcry_log_debughex; gcry_log_debugmpi; gcry_log_debugpnt; gcry_log_debugsxp;
 
+    gcry_get_config;
+
     _gcry_mpi_get_const;
 
     gcry_ctx_release;
index 9d8b7bd..002a84f 100644 (file)
@@ -198,18 +198,6 @@ _gcry_log_info( const char *fmt, ... )
     va_end(arg_ptr);
 }
 
-int
-_gcry_log_info_with_dummy_fp (FILE *fp, const char *fmt, ... )
-{
-    va_list arg_ptr;
-
-    (void)fp;
-    va_start( arg_ptr, fmt ) ;
-    _gcry_logv( GCRY_LOG_INFO, fmt, arg_ptr );
-    va_end(arg_ptr);
-    return 0;
-}
-
 void
 _gcry_log_error( const char *fmt, ... )
 {
index 3abbd37..7bf3d57 100644 (file)
@@ -1435,6 +1435,12 @@ gcry_log_debugsxp (const char *text, gcry_sexp_t sexp)
   _gcry_log_printsxp (text, sexp);
 }
 
+char *
+gcry_get_config (int mode, const char *what)
+{
+  return _gcry_get_config (mode, what);
+}
+
 void
 gcry_set_progress_handler (gcry_handler_progress_t cb, void *cb_data)
 {
index 7ecd75e..d28993a 100644 (file)
@@ -279,6 +279,8 @@ MARK_VISIBLEX (gcry_log_debugmpi)
 MARK_VISIBLEX (gcry_log_debugpnt)
 MARK_VISIBLEX (gcry_log_debugsxp)
 
+MARK_VISIBLEX (gcry_get_config)
+
 /* Functions used to implement macros.  */
 MARK_VISIBLEX (_gcry_mpi_get_const)
 
index baf984e..6a01610 100644 (file)
 #include <stdlib.h>
 #include <string.h>
 #include <stdarg.h>
+#include <errno.h>
 
 #include "../src/gcrypt-int.h"
 
 #define PGM "version"
 #include "t-common.h"
 
+static void
+test_get_config (void)
+{
+  char *string;
+
+  string = gcry_get_config (0, NULL);
+  if (!string)
+    fail ("gcry_get_config does not return anything: %s\n",
+          gpg_strerror (gpg_error_from_syserror ()));
+  else if ( !strchr (string, '\n') )
+    fail ("gcry_get_config(0, NULL) did not return multiple lines\n");
+
+  xfree (string);
+  string = gcry_get_config (0, "version");
+  if (!string)
+    fail ("gcry_get_config(\"version\") returned NULL: %s\n",
+          gpg_strerror (gpg_error_from_syserror ()));
+  else if ( strchr (string, '\n') )
+    fail ("gcry_get_config(\"version\") returned more than one line\n");
+  else if ( strncmp (string, "version:", 8) )
+    fail ("gcry_get_config(\"version\") returned wrong line\n");
+
+  /* Test an item which is not the first.  */
+  xfree (string);
+  string = gcry_get_config (0, "cpu-arch");
+  if (!string)
+    fail ("gcry_get_config(\"cpu-arch\") returned NULL: %s\n",
+          gpg_strerror (gpg_error_from_syserror ()));
+  else if ( strchr (string, '\n') )
+    fail ("gcry_get_config(\"cpu-arch\") returned more than one line\n");
+  else if ( strncmp (string, "cpu-arch:", 9) )
+    fail ("gcry_get_config(\"cpu-arch\") returned wrong line\n");
+
+  /* Test that an unknown item return sthe correct error.  */
+  xfree (string);
+  string = gcry_get_config (0, "no-such-item");
+  if (string)
+    fail ("gcry_get_config(\"no-such-item\") returned something\n");
+  else if (errno)
+    fail ("gcry_get_config(\"no-such-item\") returned wrong error: %s\n",
+          gpg_strerror (gpg_error_from_syserror ()));
+
+  xfree (string);
+}
+
 
 int
 main (int argc, char **argv)
@@ -96,5 +142,8 @@ main (int argc, char **argv)
 
   xgcry_control (GCRYCTL_PRINT_CONFIG, NULL);
 
+  test_get_config ();
+
+
   return 0;
 }