scd: More cleanup of old code.
[gnupg.git] / tools / gpgconf-comp.c
index 7470f42..0c939e5 100644 (file)
@@ -1,5 +1,6 @@
 /* gpgconf-comp.c - Configuration utility for GnuPG.
 /* gpgconf-comp.c - Configuration utility for GnuPG.
- * Copyright (C) 2004, 2007, 2008 Free Software Foundation, Inc.
+ * Copyright (C) 2004, 2007-2011 Free Software Foundation, Inc.
+ * Copyright (C) 2016 Werner Koch
  *
  * This file is part of GnuPG.
  *
  *
  * This file is part of GnuPG.
  *
@@ -14,7 +15,7 @@
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with GnuPG; if not, see <http://www.gnu.org/licenses/>.
+ * along with GnuPG; if not, see <https://www.gnu.org/licenses/>.
  */
 
 #if HAVE_CONFIG_H
  */
 
 #if HAVE_CONFIG_H
@@ -30,7 +31,9 @@
 #include <errno.h>
 #include <time.h>
 #include <stdarg.h>
 #include <errno.h>
 #include <time.h>
 #include <stdarg.h>
-#include <signal.h>
+#ifdef HAVE_SIGNAL_H
+# include <signal.h>
+#endif
 #include <ctype.h>
 #ifdef HAVE_W32_SYSTEM
 # define WIN32_LEAN_AND_MEAN 1
 #include <ctype.h>
 #ifdef HAVE_W32_SYSTEM
 # define WIN32_LEAN_AND_MEAN 1
 #endif
 
 /* For log_logv(), asctimestamp(), gnupg_get_time ().  */
 #endif
 
 /* For log_logv(), asctimestamp(), gnupg_get_time ().  */
-#define JNLIB_NEED_LOG_LOGV
 #include "util.h"
 #include "i18n.h"
 #include "exechelp.h"
 #include "util.h"
 #include "i18n.h"
 #include "exechelp.h"
+#include "sysutils.h"
 
 #include "gc-opt-flags.h"
 #include "gpgconf.h"
 
 
 #include "gc-opt-flags.h"
 #include "gpgconf.h"
 
-
 /* There is a problem with gpg 1.4 under Windows: --gpgconf-list
    returns a plain filename without escaping.  As long as we have not
 /* There is a problem with gpg 1.4 under Windows: --gpgconf-list
    returns a plain filename without escaping.  As long as we have not
-   fixed that we need to use gpg2 - it might actually be better to use
-   gpg2 in any case.  */
-#ifdef HAVE_W32_SYSTEM
+   fixed that we need to use gpg2.  */
+#if defined(HAVE_W32_SYSTEM) && !defined(HAVE_W32CE_SYSTEM)
 #define GPGNAME "gpg2"
 #else
 #define GPGNAME "gpg2"
 #else
-#define GPGNAME "gpg"
+#define GPGNAME GPG_NAME
 #endif
 
 \f
 #endif
 
 \f
@@ -86,7 +87,7 @@ gc_error (int status, int errnum, const char *fmt, ...)
   va_list arg_ptr;
 
   va_start (arg_ptr, fmt);
   va_list arg_ptr;
 
   va_start (arg_ptr, fmt);
-  log_logv (JNLIB_LOG_ERROR, fmt, arg_ptr);
+  log_logv (GPGRT_LOG_ERROR, fmt, arg_ptr);
   va_end (arg_ptr);
 
   if (errnum)
   va_end (arg_ptr);
 
   if (errnum)
@@ -104,7 +105,9 @@ gc_error (int status, int errnum, const char *fmt, ...)
 
 \f
 /* Forward declaration.  */
 
 \f
 /* Forward declaration.  */
-void gpg_agent_runtime_change (void);
+static void gpg_agent_runtime_change (int killflag);
+static void scdaemon_runtime_change (int killflag);
+static void dirmngr_runtime_change (int killflag);
 
 /* Backend configuration.  Backends are used to decide how the default
    and current value of an option can be determined, and how the
 
 /* Backend configuration.  Backends are used to decide how the default
    and current value of an option can be determined, and how the
@@ -130,12 +133,15 @@ typedef enum
     /* The GnuPG SCDaemon.  */
     GC_BACKEND_SCDAEMON,
 
     /* The GnuPG SCDaemon.  */
     GC_BACKEND_SCDAEMON,
 
-    /* The Aegypten directory manager.  */
+    /* The GnuPG directory manager.  */
     GC_BACKEND_DIRMNGR,
 
     GC_BACKEND_DIRMNGR,
 
-    /* The LDAP server list file for the Aegypten director manager.  */
+    /* The LDAP server list file for the director manager.  */
     GC_BACKEND_DIRMNGR_LDAP_SERVER_LIST,
 
     GC_BACKEND_DIRMNGR_LDAP_SERVER_LIST,
 
+    /* The Pinentry (not a part of GnuPG, proper).  */
+    GC_BACKEND_PINENTRY,
+
     /* The number of the above entries.  */
     GC_BACKEND_NR
   } gc_backend_t;
     /* The number of the above entries.  */
     GC_BACKEND_NR
   } gc_backend_t;
@@ -155,17 +161,18 @@ static struct
 
   /* The module name (GNUPG_MODULE_NAME_foo) as defined by
      ../common/util.h.  This value is used to get the actual installed
 
   /* The module name (GNUPG_MODULE_NAME_foo) as defined by
      ../common/util.h.  This value is used to get the actual installed
-     path of the program.  0 is used if no backedn program is
+     path of the program.  0 is used if no backend program is
      available. */
   char module_name;
 
      available. */
   char module_name;
 
-  /* The runtime change callback.  */
-  void (*runtime_change) (void);
+  /* The runtime change callback.  If KILLFLAG is true the component
+     is killed and not just reloaded.  */
+  void (*runtime_change) (int killflag);
 
   /* The option name for the configuration filename of this backend.
 
   /* The option name for the configuration filename of this backend.
-     This must be an absolute pathname.  It can be an option from a
+     This must be an absolute filename.  It can be an option from a
      different backend (but then ordering of the options might
      different backend (but then ordering of the options might
-     matter).  */
+     matter).  Note: This must be unique among all components.  */
   const char *option_config_filename;
 
   /* If this is a file backend rather than a program backend, then
   const char *option_config_filename;
 
   /* If this is a file backend rather than a program backend, then
@@ -174,18 +181,20 @@ static struct
 } gc_backend[GC_BACKEND_NR] =
   {
     { NULL },          /* GC_BACKEND_ANY dummy entry.  */
 } gc_backend[GC_BACKEND_NR] =
   {
     { NULL },          /* GC_BACKEND_ANY dummy entry.  */
-    { "GnuPG", GPGNAME, GNUPG_MODULE_NAME_GPG,
-      NULL, "gpgconf-gpg.conf" },
-    { "GPGSM", "gpgsm", GNUPG_MODULE_NAME_GPGSM,
-      NULL, "gpgconf-gpgsm.conf" },
-    { "GPG Agent", "gpg-agent", GNUPG_MODULE_NAME_AGENT, 
-      gpg_agent_runtime_change, "gpgconf-gpg-agent.conf" },
-    { "SCDaemon", "scdaemon", GNUPG_MODULE_NAME_SCDAEMON,
-      NULL, "gpgconf-scdaemon.conf" },
-    { "DirMngr", "dirmngr", GNUPG_MODULE_NAME_DIRMNGR,
-      NULL, "gpgconf-dirmngr.conf" },
-    { "DirMngr LDAP Server List", NULL, 0, 
+    { GPG_DISP_NAME, GPGNAME, GNUPG_MODULE_NAME_GPG,
+      NULL, GPGCONF_NAME "-" GPG_NAME ".conf" },
+    { GPGSM_DISP_NAME, GPGSM_NAME, GNUPG_MODULE_NAME_GPGSM,
+      NULL, GPGCONF_NAME "-" GPGSM_NAME ".conf" },
+    { GPG_AGENT_DISP_NAME, GPG_AGENT_NAME, GNUPG_MODULE_NAME_AGENT,
+      gpg_agent_runtime_change, GPGCONF_NAME"-" GPG_AGENT_NAME ".conf" },
+    { SCDAEMON_DISP_NAME, SCDAEMON_NAME, GNUPG_MODULE_NAME_SCDAEMON,
+      scdaemon_runtime_change, GPGCONF_NAME"-" SCDAEMON_NAME ".conf" },
+    { DIRMNGR_DISP_NAME, DIRMNGR_NAME, GNUPG_MODULE_NAME_DIRMNGR,
+      dirmngr_runtime_change, GPGCONF_NAME "-" DIRMNGR_NAME ".conf" },
+    { DIRMNGR_DISP_NAME " LDAP Server List", NULL, 0,
       NULL, "ldapserverlist-file", "LDAP Server" },
       NULL, "ldapserverlist-file", "LDAP Server" },
+    { "Pinentry", "pinentry", GNUPG_MODULE_NAME_PINENTRY,
+      NULL, GPGCONF_NAME "-pinentry.conf" },
   };
 
 \f
   };
 
 \f
@@ -218,8 +227,8 @@ typedef enum
 
     /* Complex argument types.  */
 
 
     /* Complex argument types.  */
 
-    /* A complete pathname.  */
-    GC_ARG_TYPE_PATHNAME = 32,
+    /* A complete filename.  */
+    GC_ARG_TYPE_FILENAME = 32,
 
     /* An LDAP server in the format
        HOSTNAME:PORT:USERNAME:PASSWORD:BASE_DN.  */
 
     /* An LDAP server in the format
        HOSTNAME:PORT:USERNAME:PASSWORD:BASE_DN.  */
@@ -228,6 +237,16 @@ typedef enum
     /* A 40 character fingerprint.  */
     GC_ARG_TYPE_KEY_FPR = 34,
 
     /* A 40 character fingerprint.  */
     GC_ARG_TYPE_KEY_FPR = 34,
 
+    /* A user ID or key ID or fingerprint for a certificate.  */
+    GC_ARG_TYPE_PUB_KEY = 35,
+
+    /* A user ID or key ID or fingerprint for a certificate with a key.  */
+    GC_ARG_TYPE_SEC_KEY = 36,
+
+    /* A alias list made up of a key, an equal sign and a space
+       separated list of values.  */
+    GC_ARG_TYPE_ALIAS_LIST = 37,
+
     /* ADD NEW COMPLEX TYPE ENTRIES HERE.  */
 
     /* The number of the above entries.  */
     /* ADD NEW COMPLEX TYPE ENTRIES HERE.  */
 
     /* The number of the above entries.  */
@@ -270,9 +289,12 @@ static struct
     { GC_ARG_TYPE_NR, NULL }, { GC_ARG_TYPE_NR, NULL },
 
     /* The complex argument types have a basic type as fallback.  */
     { GC_ARG_TYPE_NR, NULL }, { GC_ARG_TYPE_NR, NULL },
 
     /* The complex argument types have a basic type as fallback.  */
-    { GC_ARG_TYPE_STRING, "pathname" },
+    { GC_ARG_TYPE_STRING, "filename" },
     { GC_ARG_TYPE_STRING, "ldap server" },
     { GC_ARG_TYPE_STRING, "key fpr" },
     { GC_ARG_TYPE_STRING, "ldap server" },
     { GC_ARG_TYPE_STRING, "key fpr" },
+    { GC_ARG_TYPE_STRING, "pub key" },
+    { GC_ARG_TYPE_STRING, "sec key" },
+    { GC_ARG_TYPE_STRING, "alias list" },
   };
 
 
   };
 
 
@@ -336,11 +358,6 @@ static struct
    several times.  A comma separated list of arguments is used as the
    argument value.  */
 #define GC_OPT_FLAG_LIST       (1UL << 2)
    several times.  A comma separated list of arguments is used as the
    argument value.  */
 #define GC_OPT_FLAG_LIST       (1UL << 2)
-/* The NO_CHANGE flag for an option indicates that the user should not
-   be allowed to change this option using the standard gpgconf method.
-   Frontends using gpgconf should grey out such options, so that only
-   the current value is displayed.  */
-#define GC_OPT_FLAG_NO_CHANGE   (1UL <<7)
 
 
 /* A human-readable description for each flag.  */
 
 
 /* A human-readable description for each flag.  */
@@ -386,17 +403,17 @@ struct gc_option
   /* A gettext domain in which the following description can be found.
      If this is NULL, then DESC is not translated.  Valid for groups
      and options.
   /* A gettext domain in which the following description can be found.
      If this is NULL, then DESC is not translated.  Valid for groups
      and options.
-     
+
      Note that we try to keep the description of groups within the
      Note that we try to keep the description of groups within the
-     gnupg domain. 
-     
+     gnupg domain.
+
      IMPORTANT: If you add a new domain please make sure to add a code
      set switching call to the function my_dgettext further below.  */
   const char *desc_domain;
 
   /* A gettext description for this group or option.  If it starts
      with a '|', then the string up to the next '|' describes the
      IMPORTANT: If you add a new domain please make sure to add a code
      set switching call to the function my_dgettext further below.  */
   const char *desc_domain;
 
   /* A gettext description for this group or option.  If it starts
      with a '|', then the string up to the next '|' describes the
-     argument, and the description follows the second '|'. 
+     argument, and the description follows the second '|'.
 
      In general enclosing these description in N_() is not required
      because the description should be identical to the one in the
 
      In general enclosing these description in N_() is not required
      because the description should be identical to the one in the
@@ -447,12 +464,16 @@ typedef struct gc_option gc_option_t;
 #define GC_OPTION_NULL { NULL }
 
 \f
 #define GC_OPTION_NULL { NULL }
 
 \f
+#ifndef BUILD_WITH_AGENT
+#define gc_options_gpg_agent NULL
+#else
 /* The options of the GC_COMPONENT_GPG_AGENT component.  */
 static gc_option_t gc_options_gpg_agent[] =
  {
    /* The configuration file to which we write the changes.  */
 /* The options of the GC_COMPONENT_GPG_AGENT component.  */
 static gc_option_t gc_options_gpg_agent[] =
  {
    /* The configuration file to which we write the changes.  */
-   { "gpgconf-gpg-agent.conf", GC_OPT_FLAG_NONE, GC_LEVEL_INTERNAL,
-     NULL, NULL, GC_ARG_TYPE_PATHNAME, GC_BACKEND_GPG_AGENT },
+   { GPGCONF_NAME"-" GPG_AGENT_NAME ".conf",
+     GC_OPT_FLAG_NONE, GC_LEVEL_INTERNAL,
+     NULL, NULL, GC_ARG_TYPE_FILENAME, GC_BACKEND_GPG_AGENT },
 
    { "Monitor",
      GC_OPT_FLAG_GROUP, GC_LEVEL_BASIC,
 
    { "Monitor",
      GC_OPT_FLAG_GROUP, GC_LEVEL_BASIC,
@@ -468,14 +489,20 @@ static gc_option_t gc_options_gpg_agent[] =
      GC_ARG_TYPE_NONE, GC_BACKEND_GPG_AGENT },
 
    { "Configuration",
      GC_ARG_TYPE_NONE, GC_BACKEND_GPG_AGENT },
 
    { "Configuration",
-     GC_OPT_FLAG_GROUP, GC_LEVEL_EXPERT,
+     GC_OPT_FLAG_GROUP, GC_LEVEL_BASIC,
      "gnupg", N_("Options controlling the configuration") },
    { "options", GC_OPT_FLAG_NONE, GC_LEVEL_EXPERT,
      "gnupg", "|FILE|read options from FILE",
      "gnupg", N_("Options controlling the configuration") },
    { "options", GC_OPT_FLAG_NONE, GC_LEVEL_EXPERT,
      "gnupg", "|FILE|read options from FILE",
-     GC_ARG_TYPE_PATHNAME, GC_BACKEND_GPG_AGENT },
+     GC_ARG_TYPE_FILENAME, GC_BACKEND_GPG_AGENT },
    { "disable-scdaemon", GC_OPT_FLAG_NONE, GC_LEVEL_ADVANCED,
      "gnupg", "do not use the SCdaemon",
      GC_ARG_TYPE_NONE, GC_BACKEND_GPG_AGENT },
    { "disable-scdaemon", GC_OPT_FLAG_NONE, GC_LEVEL_ADVANCED,
      "gnupg", "do not use the SCdaemon",
      GC_ARG_TYPE_NONE, GC_BACKEND_GPG_AGENT },
+   { "enable-ssh-support", GC_OPT_FLAG_NONE, GC_LEVEL_BASIC,
+     "gnupg", "enable ssh support",
+     GC_ARG_TYPE_NONE, GC_BACKEND_GPG_AGENT },
+   { "enable-putty-support", GC_OPT_FLAG_NONE, GC_LEVEL_BASIC,
+     "gnupg", "enable putty support",
+     GC_ARG_TYPE_NONE, GC_BACKEND_GPG_AGENT },
 
    { "Debug",
      GC_OPT_FLAG_GROUP, GC_LEVEL_ADVANCED,
 
    { "Debug",
      GC_OPT_FLAG_GROUP, GC_LEVEL_ADVANCED,
@@ -485,7 +512,7 @@ static gc_option_t gc_options_gpg_agent[] =
      GC_ARG_TYPE_STRING, GC_BACKEND_GPG_AGENT },
    { "log-file", GC_OPT_FLAG_RUNTIME, GC_LEVEL_ADVANCED,
      "gnupg", N_("|FILE|write server mode logs to FILE"),
      GC_ARG_TYPE_STRING, GC_BACKEND_GPG_AGENT },
    { "log-file", GC_OPT_FLAG_RUNTIME, GC_LEVEL_ADVANCED,
      "gnupg", N_("|FILE|write server mode logs to FILE"),
-     GC_ARG_TYPE_PATHNAME, GC_BACKEND_GPG_AGENT },
+     GC_ARG_TYPE_FILENAME, GC_BACKEND_GPG_AGENT },
    { "faked-system-time", GC_OPT_FLAG_NONE, GC_LEVEL_INVISIBLE,
      NULL, NULL,
      GC_ARG_TYPE_UINT32, GC_BACKEND_GPG_AGENT },
    { "faked-system-time", GC_OPT_FLAG_NONE, GC_LEVEL_INVISIBLE,
      NULL, NULL,
      GC_ARG_TYPE_UINT32, GC_BACKEND_GPG_AGENT },
@@ -494,7 +521,7 @@ static gc_option_t gc_options_gpg_agent[] =
      GC_OPT_FLAG_GROUP, GC_LEVEL_BASIC,
      "gnupg", N_("Options controlling the security") },
    { "default-cache-ttl", GC_OPT_FLAG_RUNTIME,
      GC_OPT_FLAG_GROUP, GC_LEVEL_BASIC,
      "gnupg", N_("Options controlling the security") },
    { "default-cache-ttl", GC_OPT_FLAG_RUNTIME,
-     GC_LEVEL_BASIC, "gnupg", 
+     GC_LEVEL_BASIC, "gnupg",
      "|N|expire cached PINs after N seconds",
      GC_ARG_TYPE_UINT32, GC_BACKEND_GPG_AGENT },
    { "default-cache-ttl-ssh", GC_OPT_FLAG_RUNTIME,
      "|N|expire cached PINs after N seconds",
      GC_ARG_TYPE_UINT32, GC_BACKEND_GPG_AGENT },
    { "default-cache-ttl-ssh", GC_OPT_FLAG_RUNTIME,
@@ -506,14 +533,24 @@ static gc_option_t gc_options_gpg_agent[] =
      N_("|N|set maximum PIN cache lifetime to N seconds"),
      GC_ARG_TYPE_UINT32, GC_BACKEND_GPG_AGENT },
    { "max-cache-ttl-ssh", GC_OPT_FLAG_RUNTIME,
      N_("|N|set maximum PIN cache lifetime to N seconds"),
      GC_ARG_TYPE_UINT32, GC_BACKEND_GPG_AGENT },
    { "max-cache-ttl-ssh", GC_OPT_FLAG_RUNTIME,
-     GC_LEVEL_EXPERT, "gnupg", 
+     GC_LEVEL_EXPERT, "gnupg",
      N_("|N|set maximum SSH key lifetime to N seconds"),
      GC_ARG_TYPE_UINT32, GC_BACKEND_GPG_AGENT },
    { "ignore-cache-for-signing", GC_OPT_FLAG_RUNTIME,
      GC_LEVEL_BASIC, "gnupg", "do not use the PIN cache when signing",
      GC_ARG_TYPE_NONE, GC_BACKEND_GPG_AGENT },
      N_("|N|set maximum SSH key lifetime to N seconds"),
      GC_ARG_TYPE_UINT32, GC_BACKEND_GPG_AGENT },
    { "ignore-cache-for-signing", GC_OPT_FLAG_RUNTIME,
      GC_LEVEL_BASIC, "gnupg", "do not use the PIN cache when signing",
      GC_ARG_TYPE_NONE, GC_BACKEND_GPG_AGENT },
-   { "allow-mark-trusted", GC_OPT_FLAG_RUNTIME,
-     GC_LEVEL_ADVANCED, "gnupg", "allow clients to mark keys as \"trusted\"",
+   { "allow-emacs-pinentry", GC_OPT_FLAG_RUNTIME,
+     GC_LEVEL_ADVANCED,
+     "gnupg", "allow passphrase to be prompted through Emacs",
+     GC_ARG_TYPE_NONE, GC_BACKEND_GPG_AGENT },
+   { "no-allow-external-cache", GC_OPT_FLAG_RUNTIME,
+     GC_LEVEL_BASIC, "gnupg", "disallow the use of an external password cache",
+     GC_ARG_TYPE_NONE, GC_BACKEND_GPG_AGENT },
+   { "no-allow-mark-trusted", GC_OPT_FLAG_RUNTIME,
+     GC_LEVEL_ADVANCED, "gnupg", "disallow clients to mark keys as \"trusted\"",
+     GC_ARG_TYPE_NONE, GC_BACKEND_GPG_AGENT },
+   { "no-allow-loopback-pinentry", GC_OPT_FLAG_RUNTIME,
+     GC_LEVEL_EXPERT, "gnupg", "disallow caller to override the pinentry",
      GC_ARG_TYPE_NONE, GC_BACKEND_GPG_AGENT },
    { "no-grab", GC_OPT_FLAG_RUNTIME, GC_LEVEL_EXPERT,
      "gnupg", "do not grab keyboard and mouse",
      GC_ARG_TYPE_NONE, GC_BACKEND_GPG_AGENT },
    { "no-grab", GC_OPT_FLAG_RUNTIME, GC_LEVEL_EXPERT,
      "gnupg", "do not grab keyboard and mouse",
@@ -522,46 +559,55 @@ static gc_option_t gc_options_gpg_agent[] =
    { "Passphrase policy",
      GC_OPT_FLAG_GROUP, GC_LEVEL_ADVANCED,
      "gnupg", N_("Options enforcing a passphrase policy") },
    { "Passphrase policy",
      GC_OPT_FLAG_GROUP, GC_LEVEL_ADVANCED,
      "gnupg", N_("Options enforcing a passphrase policy") },
-   { "enforce-passphrase-constraints", GC_OPT_FLAG_RUNTIME, 
-     GC_LEVEL_EXPERT, "gnupg", 
-     N_("do not allow to bypass the passphrase policy"),
+   { "enforce-passphrase-constraints", GC_OPT_FLAG_RUNTIME,
+     GC_LEVEL_EXPERT, "gnupg",
+     N_("do not allow bypassing the passphrase policy"),
      GC_ARG_TYPE_NONE, GC_BACKEND_GPG_AGENT },
    { "min-passphrase-len", GC_OPT_FLAG_RUNTIME,
      GC_ARG_TYPE_NONE, GC_BACKEND_GPG_AGENT },
    { "min-passphrase-len", GC_OPT_FLAG_RUNTIME,
-     GC_LEVEL_ADVANCED, "gnupg", 
+     GC_LEVEL_ADVANCED, "gnupg",
      N_("|N|set minimal required length for new passphrases to N"),
      GC_ARG_TYPE_UINT32, GC_BACKEND_GPG_AGENT },
    { "min-passphrase-nonalpha", GC_OPT_FLAG_RUNTIME,
      N_("|N|set minimal required length for new passphrases to N"),
      GC_ARG_TYPE_UINT32, GC_BACKEND_GPG_AGENT },
    { "min-passphrase-nonalpha", GC_OPT_FLAG_RUNTIME,
-     GC_LEVEL_EXPERT, "gnupg", 
+     GC_LEVEL_EXPERT, "gnupg",
      N_("|N|require at least N non-alpha characters for a new passphrase"),
      GC_ARG_TYPE_UINT32, GC_BACKEND_GPG_AGENT },
    { "check-passphrase-pattern", GC_OPT_FLAG_RUNTIME,
      GC_LEVEL_EXPERT,
      "gnupg", N_("|FILE|check new passphrases against pattern in FILE"),
      N_("|N|require at least N non-alpha characters for a new passphrase"),
      GC_ARG_TYPE_UINT32, GC_BACKEND_GPG_AGENT },
    { "check-passphrase-pattern", GC_OPT_FLAG_RUNTIME,
      GC_LEVEL_EXPERT,
      "gnupg", N_("|FILE|check new passphrases against pattern in FILE"),
-     GC_ARG_TYPE_PATHNAME, GC_BACKEND_GPG_AGENT },
+     GC_ARG_TYPE_FILENAME, GC_BACKEND_GPG_AGENT },
    { "max-passphrase-days", GC_OPT_FLAG_RUNTIME,
    { "max-passphrase-days", GC_OPT_FLAG_RUNTIME,
-     GC_LEVEL_EXPERT, "gnupg", 
+     GC_LEVEL_EXPERT, "gnupg",
      N_("|N|expire the passphrase after N days"),
      GC_ARG_TYPE_UINT32, GC_BACKEND_GPG_AGENT },
      N_("|N|expire the passphrase after N days"),
      GC_ARG_TYPE_UINT32, GC_BACKEND_GPG_AGENT },
-   { "enable-passphrase-history", GC_OPT_FLAG_RUNTIME, 
-     GC_LEVEL_EXPERT, "gnupg", 
+   { "enable-passphrase-history", GC_OPT_FLAG_RUNTIME,
+     GC_LEVEL_EXPERT, "gnupg",
      N_("do not allow the reuse of old passphrases"),
      GC_ARG_TYPE_NONE, GC_BACKEND_GPG_AGENT },
      N_("do not allow the reuse of old passphrases"),
      GC_ARG_TYPE_NONE, GC_BACKEND_GPG_AGENT },
+   { "pinentry-timeout", GC_OPT_FLAG_RUNTIME,
+     GC_LEVEL_ADVANCED, "gnupg",
+     N_("|N|set the Pinentry timeout to N seconds"),
+     GC_ARG_TYPE_UINT32, GC_BACKEND_GPG_AGENT },
 
    GC_OPTION_NULL
  };
 
    GC_OPTION_NULL
  };
+#endif /*BUILD_WITH_AGENT*/
 
 
 
 
+#ifndef BUILD_WITH_SCDAEMON
+#define gc_options_scdaemon NULL
+#else
 /* The options of the GC_COMPONENT_SCDAEMON component.  */
 static gc_option_t gc_options_scdaemon[] =
  {
    /* The configuration file to which we write the changes.  */
 /* The options of the GC_COMPONENT_SCDAEMON component.  */
 static gc_option_t gc_options_scdaemon[] =
  {
    /* The configuration file to which we write the changes.  */
-   { "gpgconf-scdaemon.conf", GC_OPT_FLAG_NONE, GC_LEVEL_INTERNAL,
-     NULL, NULL, GC_ARG_TYPE_PATHNAME, GC_BACKEND_SCDAEMON },
+   { GPGCONF_NAME"-"SCDAEMON_NAME".conf",
+     GC_OPT_FLAG_NONE, GC_LEVEL_INTERNAL,
+     NULL, NULL, GC_ARG_TYPE_FILENAME, GC_BACKEND_SCDAEMON },
 
    { "Monitor",
      GC_OPT_FLAG_GROUP, GC_LEVEL_BASIC,
      "gnupg", N_("Options controlling the diagnostic output") },
 
    { "Monitor",
      GC_OPT_FLAG_GROUP, GC_LEVEL_BASIC,
      "gnupg", N_("Options controlling the diagnostic output") },
-   { "verbose", GC_OPT_FLAG_LIST, GC_LEVEL_BASIC,
+   { "verbose", GC_OPT_FLAG_LIST|GC_OPT_FLAG_RUNTIME, GC_LEVEL_BASIC,
      "gnupg", "verbose",
      GC_ARG_TYPE_NONE, GC_BACKEND_SCDAEMON },
    { "quiet", GC_OPT_FLAG_NONE, GC_LEVEL_BASIC,
      "gnupg", "verbose",
      GC_ARG_TYPE_NONE, GC_BACKEND_SCDAEMON },
    { "quiet", GC_OPT_FLAG_NONE, GC_LEVEL_BASIC,
@@ -576,54 +622,62 @@ static gc_option_t gc_options_scdaemon[] =
      "gnupg", N_("Options controlling the configuration") },
    { "options", GC_OPT_FLAG_NONE, GC_LEVEL_EXPERT,
      "gnupg", "|FILE|read options from FILE",
      "gnupg", N_("Options controlling the configuration") },
    { "options", GC_OPT_FLAG_NONE, GC_LEVEL_EXPERT,
      "gnupg", "|FILE|read options from FILE",
-     GC_ARG_TYPE_PATHNAME, GC_BACKEND_SCDAEMON },
-   { "reader-port", GC_OPT_FLAG_NONE, GC_LEVEL_BASIC,
+     GC_ARG_TYPE_FILENAME, GC_BACKEND_SCDAEMON },
+   { "reader-port", GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME, GC_LEVEL_BASIC,
      "gnupg", "|N|connect to reader at port N",
      GC_ARG_TYPE_STRING, GC_BACKEND_SCDAEMON },
      "gnupg", "|N|connect to reader at port N",
      GC_ARG_TYPE_STRING, GC_BACKEND_SCDAEMON },
-   { "ctapi-driver", GC_OPT_FLAG_NONE, GC_LEVEL_ADVANCED,
+   { "ctapi-driver", GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME, GC_LEVEL_ADVANCED,
      "gnupg", "|NAME|use NAME as ct-API driver",
      GC_ARG_TYPE_STRING, GC_BACKEND_SCDAEMON },
      "gnupg", "|NAME|use NAME as ct-API driver",
      GC_ARG_TYPE_STRING, GC_BACKEND_SCDAEMON },
-   { "pcsc-driver", GC_OPT_FLAG_NONE, GC_LEVEL_ADVANCED,
+   { "pcsc-driver", GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME, GC_LEVEL_ADVANCED,
      "gnupg", "|NAME|use NAME as PC/SC driver",
      GC_ARG_TYPE_STRING, GC_BACKEND_SCDAEMON },
      "gnupg", "|NAME|use NAME as PC/SC driver",
      GC_ARG_TYPE_STRING, GC_BACKEND_SCDAEMON },
-   { "disable-opensc", GC_OPT_FLAG_NONE, GC_LEVEL_EXPERT,
-     "gnupg", "do not use the OpenSC layer",
-     GC_ARG_TYPE_NONE, GC_BACKEND_SCDAEMON },
-   { "disable-ccid", GC_OPT_FLAG_NONE, GC_LEVEL_EXPERT,
+   { "disable-ccid", GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME, GC_LEVEL_EXPERT,
      "gnupg", "do not use the internal CCID driver",
      GC_ARG_TYPE_NONE, GC_BACKEND_SCDAEMON },
      "gnupg", "do not use the internal CCID driver",
      GC_ARG_TYPE_NONE, GC_BACKEND_SCDAEMON },
-   { "disable-keypad", GC_OPT_FLAG_NONE, GC_LEVEL_BASIC,
-     "gnupg", "do not use a reader's keypad",
+   { "disable-pinpad", GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME, GC_LEVEL_BASIC,
+     "gnupg", "do not use a reader's pinpad",
+     GC_ARG_TYPE_NONE, GC_BACKEND_SCDAEMON },
+   { "enable-pinpad-varlen",
+     GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME, GC_LEVEL_BASIC,
+     "gnupg", "use variable length input for pinpad",
      GC_ARG_TYPE_NONE, GC_BACKEND_SCDAEMON },
      GC_ARG_TYPE_NONE, GC_BACKEND_SCDAEMON },
+   { "card-timeout", GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME, GC_LEVEL_BASIC,
+     "gnupg", "|N|disconnect the card after N seconds of inactivity",
+     GC_ARG_TYPE_UINT32, GC_BACKEND_SCDAEMON },
 
    { "Debug",
      GC_OPT_FLAG_GROUP, GC_LEVEL_ADVANCED,
      "gnupg", N_("Options useful for debugging") },
 
    { "Debug",
      GC_OPT_FLAG_GROUP, GC_LEVEL_ADVANCED,
      "gnupg", N_("Options useful for debugging") },
-   { "debug-level", GC_OPT_FLAG_ARG_OPT, GC_LEVEL_ADVANCED,
+   { "debug-level", GC_OPT_FLAG_ARG_OPT|GC_OPT_FLAG_RUNTIME, GC_LEVEL_ADVANCED,
      "gnupg", "|LEVEL|set the debugging level to LEVEL",
      GC_ARG_TYPE_STRING, GC_BACKEND_SCDAEMON },
      "gnupg", "|LEVEL|set the debugging level to LEVEL",
      GC_ARG_TYPE_STRING, GC_BACKEND_SCDAEMON },
-   { "log-file", GC_OPT_FLAG_NONE, GC_LEVEL_ADVANCED,
-     "gnupg", N_("|FILE|write server mode logs to FILE"),
-     GC_ARG_TYPE_PATHNAME, GC_BACKEND_SCDAEMON },
+   { "log-file", GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME, GC_LEVEL_ADVANCED,
+     "gnupg", N_("|FILE|write a log to FILE"),
+     GC_ARG_TYPE_FILENAME, GC_BACKEND_SCDAEMON },
 
    { "Security",
      GC_OPT_FLAG_GROUP, GC_LEVEL_BASIC,
      "gnupg", N_("Options controlling the security") },
 
    { "Security",
      GC_OPT_FLAG_GROUP, GC_LEVEL_BASIC,
      "gnupg", N_("Options controlling the security") },
-   { "allow-admin", GC_OPT_FLAG_NONE, GC_LEVEL_BASIC,
-     "gnupg", "allow the use of admin card commands",
+   { "deny-admin", GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME, GC_LEVEL_BASIC,
+     "gnupg", "deny the use of admin card commands",
      GC_ARG_TYPE_NONE, GC_BACKEND_SCDAEMON },
 
 
    GC_OPTION_NULL
  };
      GC_ARG_TYPE_NONE, GC_BACKEND_SCDAEMON },
 
 
    GC_OPTION_NULL
  };
+#endif /*BUILD_WITH_SCDAEMON*/
 
 
-
+#ifndef BUILD_WITH_GPG
+#define gc_options_gpg NULL
+#else
 /* The options of the GC_COMPONENT_GPG component.  */
 static gc_option_t gc_options_gpg[] =
  {
    /* The configuration file to which we write the changes.  */
 /* The options of the GC_COMPONENT_GPG component.  */
 static gc_option_t gc_options_gpg[] =
  {
    /* The configuration file to which we write the changes.  */
-   { "gpgconf-gpg.conf", GC_OPT_FLAG_NONE, GC_LEVEL_INTERNAL,
-     NULL, NULL, GC_ARG_TYPE_PATHNAME, GC_BACKEND_GPG },
+   { GPGCONF_NAME"-"GPG_NAME".conf",
+     GC_OPT_FLAG_NONE, GC_LEVEL_INTERNAL,
+     NULL, NULL, GC_ARG_TYPE_FILENAME, GC_BACKEND_GPG },
 
    { "Monitor",
      GC_OPT_FLAG_GROUP, GC_LEVEL_BASIC,
 
    { "Monitor",
      GC_OPT_FLAG_GROUP, GC_LEVEL_BASIC,
@@ -647,9 +701,27 @@ static gc_option_t gc_options_gpg[] =
    { "encrypt-to", GC_OPT_FLAG_NONE, GC_LEVEL_BASIC,
      "gnupg", N_("|NAME|encrypt to user ID NAME as well"),
      GC_ARG_TYPE_STRING, GC_BACKEND_GPG },
    { "encrypt-to", GC_OPT_FLAG_NONE, GC_LEVEL_BASIC,
      "gnupg", N_("|NAME|encrypt to user ID NAME as well"),
      GC_ARG_TYPE_STRING, GC_BACKEND_GPG },
-   { "options", GC_OPT_FLAG_NONE, GC_LEVEL_EXPERT,
-     "gnupg", "|FILE|read options from FILE",
-     GC_ARG_TYPE_PATHNAME, GC_BACKEND_GPG },
+   { "group", GC_OPT_FLAG_LIST, GC_LEVEL_ADVANCED,
+     "gnupg", N_("|SPEC|set up email aliases"),
+     GC_ARG_TYPE_ALIAS_LIST, GC_BACKEND_GPG },
+   { "options", GC_OPT_FLAG_NONE, GC_LEVEL_INVISIBLE,
+     NULL, NULL,
+     GC_ARG_TYPE_FILENAME, GC_BACKEND_GPG },
+   { "compliance", GC_OPT_FLAG_NONE, GC_LEVEL_INVISIBLE,
+     NULL, NULL,
+     GC_ARG_TYPE_STRING, GC_BACKEND_GPG },
+   { "default-new-key-algo", GC_OPT_FLAG_NONE, GC_LEVEL_INVISIBLE,
+     NULL, NULL,
+     GC_ARG_TYPE_STRING, GC_BACKEND_GPG },
+   { "default_pubkey_algo",
+     (GC_OPT_FLAG_ARG_OPT|GC_OPT_FLAG_NO_CHANGE), GC_LEVEL_INVISIBLE,
+     NULL, NULL,
+     GC_ARG_TYPE_STRING, GC_BACKEND_GPG },
+   { "trust-model",
+     GC_OPT_FLAG_NONE, GC_LEVEL_INVISIBLE,
+     NULL, NULL,
+     GC_ARG_TYPE_STRING, GC_BACKEND_GPG },
+
 
    { "Debug",
      GC_OPT_FLAG_GROUP, GC_LEVEL_ADVANCED,
 
    { "Debug",
      GC_OPT_FLAG_GROUP, GC_LEVEL_ADVANCED,
@@ -659,7 +731,7 @@ static gc_option_t gc_options_gpg[] =
      GC_ARG_TYPE_STRING, GC_BACKEND_GPG },
    { "log-file", GC_OPT_FLAG_NONE, GC_LEVEL_ADVANCED,
      "gnupg", N_("|FILE|write server mode logs to FILE"),
      GC_ARG_TYPE_STRING, GC_BACKEND_GPG },
    { "log-file", GC_OPT_FLAG_NONE, GC_LEVEL_ADVANCED,
      "gnupg", N_("|FILE|write server mode logs to FILE"),
-     GC_ARG_TYPE_PATHNAME, GC_BACKEND_GPG },
+     GC_ARG_TYPE_FILENAME, GC_BACKEND_GPG },
 /*    { "faked-system-time", GC_OPT_FLAG_NONE, GC_LEVEL_INVISIBLE, */
 /*      NULL, NULL, */
 /*      GC_ARG_TYPE_UINT32, GC_BACKEND_GPG }, */
 /*    { "faked-system-time", GC_OPT_FLAG_NONE, GC_LEVEL_INVISIBLE, */
 /*      NULL, NULL, */
 /*      GC_ARG_TYPE_UINT32, GC_BACKEND_GPG }, */
@@ -667,25 +739,34 @@ static gc_option_t gc_options_gpg[] =
    { "Keyserver",
      GC_OPT_FLAG_GROUP, GC_LEVEL_BASIC,
      "gnupg", N_("Configuration for Keyservers") },
    { "Keyserver",
      GC_OPT_FLAG_GROUP, GC_LEVEL_BASIC,
      "gnupg", N_("Configuration for Keyservers") },
-   { "keyserver", GC_OPT_FLAG_NONE, GC_LEVEL_BASIC,
-     "gnupg", N_("|URL|use keyserver at URL"),
+   { "keyserver", GC_OPT_FLAG_NONE, GC_LEVEL_EXPERT,
+     "gnupg", N_("|URL|use keyserver at URL"), /* Deprecated - use dirmngr */
      GC_ARG_TYPE_STRING, GC_BACKEND_GPG },
    { "allow-pka-lookup", GC_OPT_FLAG_NONE, GC_LEVEL_BASIC,
      "gnupg", N_("allow PKA lookups (DNS requests)"),
      GC_ARG_TYPE_NONE, GC_BACKEND_GPG },
      GC_ARG_TYPE_STRING, GC_BACKEND_GPG },
    { "allow-pka-lookup", GC_OPT_FLAG_NONE, GC_LEVEL_BASIC,
      "gnupg", N_("allow PKA lookups (DNS requests)"),
      GC_ARG_TYPE_NONE, GC_BACKEND_GPG },
+   { "auto-key-locate", GC_OPT_FLAG_NONE, GC_LEVEL_ADVANCED,
+     "gnupg", N_("|MECHANISMS|use MECHANISMS to locate keys by mail address"),
+     GC_ARG_TYPE_STRING, GC_BACKEND_GPG },
+   { "auto-key-retrieve", GC_OPT_FLAG_NONE, GC_LEVEL_INVISIBLE,
+     NULL, NULL, GC_ARG_TYPE_NONE, GC_BACKEND_GPG },
 
 
    GC_OPTION_NULL
  };
 
 
    GC_OPTION_NULL
  };
+#endif /*BUILD_WITH_GPG*/
 
 
 
 
-
+#ifndef BUILD_WITH_GPGSM
+#define gc_options_gpgsm NULL
+#else
 /* The options of the GC_COMPONENT_GPGSM component.  */
 static gc_option_t gc_options_gpgsm[] =
  {
    /* The configuration file to which we write the changes.  */
 /* The options of the GC_COMPONENT_GPGSM component.  */
 static gc_option_t gc_options_gpgsm[] =
  {
    /* The configuration file to which we write the changes.  */
-   { "gpgconf-gpgsm.conf", GC_OPT_FLAG_NONE, GC_LEVEL_INTERNAL,
-     NULL, NULL, GC_ARG_TYPE_PATHNAME, GC_BACKEND_GPGSM },
+   { GPGCONF_NAME"-"GPGSM_NAME".conf",
+     GC_OPT_FLAG_NONE, GC_LEVEL_INTERNAL,
+     NULL, NULL, GC_ARG_TYPE_FILENAME, GC_BACKEND_GPGSM },
 
    { "Monitor",
      GC_OPT_FLAG_GROUP, GC_LEVEL_BASIC,
 
    { "Monitor",
      GC_OPT_FLAG_GROUP, GC_LEVEL_BASIC,
@@ -711,13 +792,23 @@ static gc_option_t gc_options_gpgsm[] =
      GC_ARG_TYPE_STRING, GC_BACKEND_GPGSM },
    { "options", GC_OPT_FLAG_NONE, GC_LEVEL_EXPERT,
      "gnupg", "|FILE|read options from FILE",
      GC_ARG_TYPE_STRING, GC_BACKEND_GPGSM },
    { "options", GC_OPT_FLAG_NONE, GC_LEVEL_EXPERT,
      "gnupg", "|FILE|read options from FILE",
-     GC_ARG_TYPE_PATHNAME, GC_BACKEND_GPGSM },
+     GC_ARG_TYPE_FILENAME, GC_BACKEND_GPGSM },
    { "prefer-system-dirmngr", GC_OPT_FLAG_NONE, GC_LEVEL_ADVANCED,
      "gnupg", "use system's dirmngr if available",
      GC_ARG_TYPE_NONE, GC_BACKEND_GPGSM },
    { "prefer-system-dirmngr", GC_OPT_FLAG_NONE, GC_LEVEL_ADVANCED,
      "gnupg", "use system's dirmngr if available",
      GC_ARG_TYPE_NONE, GC_BACKEND_GPGSM },
+   { "disable-dirmngr", GC_OPT_FLAG_NONE, GC_LEVEL_EXPERT,
+     "gnupg", N_("disable all access to the dirmngr"),
+     GC_ARG_TYPE_NONE, GC_BACKEND_GPGSM },
    { "p12-charset", GC_OPT_FLAG_NONE, GC_LEVEL_ADVANCED,
      "gnupg", N_("|NAME|use encoding NAME for PKCS#12 passphrases"),
      GC_ARG_TYPE_STRING, GC_BACKEND_GPGSM },
    { "p12-charset", GC_OPT_FLAG_NONE, GC_LEVEL_ADVANCED,
      "gnupg", N_("|NAME|use encoding NAME for PKCS#12 passphrases"),
      GC_ARG_TYPE_STRING, GC_BACKEND_GPGSM },
+   { "keyserver", GC_OPT_FLAG_LIST, GC_LEVEL_BASIC,
+     "gnupg", N_("|SPEC|use this keyserver to lookup keys"),
+     GC_ARG_TYPE_LDAP_SERVER, GC_BACKEND_GPGSM },
+   { "default_pubkey_algo",
+     (GC_OPT_FLAG_ARG_OPT|GC_OPT_FLAG_NO_CHANGE), GC_LEVEL_INVISIBLE,
+     NULL, NULL,
+     GC_ARG_TYPE_STRING, GC_BACKEND_GPGSM },
 
    { "Debug",
      GC_OPT_FLAG_GROUP, GC_LEVEL_ADVANCED,
 
    { "Debug",
      GC_OPT_FLAG_GROUP, GC_LEVEL_ADVANCED,
@@ -727,7 +818,7 @@ static gc_option_t gc_options_gpgsm[] =
      GC_ARG_TYPE_STRING, GC_BACKEND_GPGSM },
    { "log-file", GC_OPT_FLAG_NONE, GC_LEVEL_ADVANCED,
      "gnupg", N_("|FILE|write server mode logs to FILE"),
      GC_ARG_TYPE_STRING, GC_BACKEND_GPGSM },
    { "log-file", GC_OPT_FLAG_NONE, GC_LEVEL_ADVANCED,
      "gnupg", N_("|FILE|write server mode logs to FILE"),
-     GC_ARG_TYPE_PATHNAME, GC_BACKEND_GPGSM },
+     GC_ARG_TYPE_FILENAME, GC_BACKEND_GPGSM },
    { "faked-system-time", GC_OPT_FLAG_NONE, GC_LEVEL_INVISIBLE,
      NULL, NULL,
      GC_ARG_TYPE_UINT32, GC_BACKEND_GPGSM },
    { "faked-system-time", GC_OPT_FLAG_NONE, GC_LEVEL_INVISIBLE,
      NULL, NULL,
      GC_ARG_TYPE_UINT32, GC_BACKEND_GPGSM },
@@ -738,6 +829,9 @@ static gc_option_t gc_options_gpgsm[] =
    { "disable-crl-checks", GC_OPT_FLAG_NONE, GC_LEVEL_BASIC,
      "gnupg", "never consult a CRL",
      GC_ARG_TYPE_NONE, GC_BACKEND_GPGSM },
    { "disable-crl-checks", GC_OPT_FLAG_NONE, GC_LEVEL_BASIC,
      "gnupg", "never consult a CRL",
      GC_ARG_TYPE_NONE, GC_BACKEND_GPGSM },
+   { "enable-crl-checks", GC_OPT_FLAG_NONE, GC_LEVEL_INVISIBLE,
+     NULL, NULL,
+     GC_ARG_TYPE_NONE, GC_BACKEND_GPGSM },
    { "disable-trusted-cert-crl-check", GC_OPT_FLAG_NONE, GC_LEVEL_EXPERT,
      "gnupg", N_("do not check CRLs for root certificates"),
      GC_ARG_TYPE_NONE, GC_BACKEND_GPGSM },
    { "disable-trusted-cert-crl-check", GC_OPT_FLAG_NONE, GC_LEVEL_EXPERT,
      "gnupg", N_("do not check CRLs for root certificates"),
      GC_ARG_TYPE_NONE, GC_BACKEND_GPGSM },
@@ -759,14 +853,19 @@ static gc_option_t gc_options_gpgsm[] =
 
    GC_OPTION_NULL
  };
 
    GC_OPTION_NULL
  };
+#endif /*BUILD_WITH_GPGSM*/
 
 
 
 
+#ifndef BUILD_WITH_DIRMNGR
+#define gc_options_dirmngr NULL
+#else
 /* The options of the GC_COMPONENT_DIRMNGR component.  */
 static gc_option_t gc_options_dirmngr[] =
  {
    /* The configuration file to which we write the changes.  */
 /* The options of the GC_COMPONENT_DIRMNGR component.  */
 static gc_option_t gc_options_dirmngr[] =
  {
    /* The configuration file to which we write the changes.  */
-   { "gpgconf-dirmngr.conf", GC_OPT_FLAG_NONE, GC_LEVEL_INTERNAL,
-     NULL, NULL, GC_ARG_TYPE_PATHNAME, GC_BACKEND_DIRMNGR },
+   { GPGCONF_NAME"-"DIRMNGR_NAME".conf",
+     GC_OPT_FLAG_NONE, GC_LEVEL_INTERNAL,
+     NULL, NULL, GC_ARG_TYPE_FILENAME, GC_BACKEND_DIRMNGR },
 
    { "Monitor",
      GC_OPT_FLAG_GROUP, GC_LEVEL_BASIC,
 
    { "Monitor",
      GC_OPT_FLAG_GROUP, GC_LEVEL_BASIC,
@@ -790,13 +889,19 @@ static gc_option_t gc_options_dirmngr[] =
    { "csh", GC_OPT_FLAG_NONE, GC_LEVEL_BASIC,
      "dirmngr", "csh-style command output",
      GC_ARG_TYPE_NONE, GC_BACKEND_DIRMNGR },
    { "csh", GC_OPT_FLAG_NONE, GC_LEVEL_BASIC,
      "dirmngr", "csh-style command output",
      GC_ARG_TYPE_NONE, GC_BACKEND_DIRMNGR },
-   
+
    { "Configuration",
      GC_OPT_FLAG_GROUP, GC_LEVEL_EXPERT,
      "gnupg", N_("Options controlling the configuration") },
    { "options", GC_OPT_FLAG_NONE, GC_LEVEL_EXPERT,
      "dirmngr", "|FILE|read options from FILE",
    { "Configuration",
      GC_OPT_FLAG_GROUP, GC_LEVEL_EXPERT,
      "gnupg", N_("Options controlling the configuration") },
    { "options", GC_OPT_FLAG_NONE, GC_LEVEL_EXPERT,
      "dirmngr", "|FILE|read options from FILE",
-     GC_ARG_TYPE_PATHNAME, GC_BACKEND_DIRMNGR },
+     GC_ARG_TYPE_FILENAME, GC_BACKEND_DIRMNGR },
+   { "resolver-timeout", GC_OPT_FLAG_NONE, GC_LEVEL_INVISIBLE,
+     NULL, NULL,
+     GC_ARG_TYPE_INT32, GC_BACKEND_DIRMNGR },
+   { "nameserver", GC_OPT_FLAG_NONE, GC_LEVEL_INVISIBLE,
+     NULL, NULL,
+     GC_ARG_TYPE_STRING, GC_BACKEND_DIRMNGR },
 
    { "Debug",
      GC_OPT_FLAG_GROUP, GC_LEVEL_ADVANCED,
 
    { "Debug",
      GC_OPT_FLAG_GROUP, GC_LEVEL_ADVANCED,
@@ -809,7 +914,7 @@ static gc_option_t gc_options_dirmngr[] =
      GC_ARG_TYPE_NONE, GC_BACKEND_DIRMNGR },
    { "log-file", GC_OPT_FLAG_NONE, GC_LEVEL_ADVANCED,
      "dirmngr", N_("|FILE|write server mode logs to FILE"),
      GC_ARG_TYPE_NONE, GC_BACKEND_DIRMNGR },
    { "log-file", GC_OPT_FLAG_NONE, GC_LEVEL_ADVANCED,
      "dirmngr", N_("|FILE|write server mode logs to FILE"),
-     GC_ARG_TYPE_PATHNAME, GC_BACKEND_DIRMNGR },
+     GC_ARG_TYPE_FILENAME, GC_BACKEND_DIRMNGR },
    { "debug-wait", GC_OPT_FLAG_NONE, GC_LEVEL_INVISIBLE,
      NULL, NULL,
      GC_ARG_TYPE_UINT32, GC_BACKEND_DIRMNGR },
    { "debug-wait", GC_OPT_FLAG_NONE, GC_LEVEL_INVISIBLE,
      NULL, NULL,
      GC_ARG_TYPE_UINT32, GC_BACKEND_DIRMNGR },
@@ -826,6 +931,23 @@ static gc_option_t gc_options_dirmngr[] =
    { "force", GC_OPT_FLAG_NONE, GC_LEVEL_BASIC,
      "dirmngr", "force loading of outdated CRLs",
      GC_ARG_TYPE_NONE, GC_BACKEND_DIRMNGR },
    { "force", GC_OPT_FLAG_NONE, GC_LEVEL_BASIC,
      "dirmngr", "force loading of outdated CRLs",
      GC_ARG_TYPE_NONE, GC_BACKEND_DIRMNGR },
+   { "allow-version-check", GC_OPT_FLAG_NONE, GC_LEVEL_BASIC,
+     "dirmngr", "allow online software version check",
+     GC_ARG_TYPE_NONE, GC_BACKEND_DIRMNGR },
+
+   { "Tor",
+     GC_OPT_FLAG_GROUP, GC_LEVEL_BASIC,
+     "gnupg", N_("Options controlling the use of Tor") },
+   { "use-tor", GC_OPT_FLAG_NONE, GC_LEVEL_BASIC,
+     "dirmngr", "route all network traffic via TOR",
+      GC_ARG_TYPE_NONE, GC_BACKEND_DIRMNGR },
+
+   { "Keyserver",
+     GC_OPT_FLAG_GROUP, GC_LEVEL_BASIC,
+     "gnupg", N_("Configuration for Keyservers") },
+   { "keyserver", GC_OPT_FLAG_NONE, GC_LEVEL_BASIC,
+     "gnupg", N_("|URL|use keyserver at URL"),
+     GC_ARG_TYPE_STRING, GC_BACKEND_DIRMNGR },
 
    { "HTTP",
      GC_OPT_FLAG_GROUP, GC_LEVEL_ADVANCED,
 
    { "HTTP",
      GC_OPT_FLAG_GROUP, GC_LEVEL_ADVANCED,
@@ -869,7 +991,7 @@ static gc_option_t gc_options_dirmngr[] =
    { "ldapserverlist-file",
      GC_OPT_FLAG_NONE, GC_LEVEL_INTERNAL,
      "dirmngr", "|FILE|read LDAP server list from FILE",
    { "ldapserverlist-file",
      GC_OPT_FLAG_NONE, GC_LEVEL_INTERNAL,
      "dirmngr", "|FILE|read LDAP server list from FILE",
-     GC_ARG_TYPE_PATHNAME, GC_BACKEND_DIRMNGR },
+     GC_ARG_TYPE_FILENAME, GC_BACKEND_DIRMNGR },
    /* This entry must come after at least one entry for
       GC_BACKEND_DIRMNGR in this component, so that the entry for
       "ldapserverlist-file will be initialized before this one.  */
    /* This entry must come after at least one entry for
       GC_BACKEND_DIRMNGR in this component, so that the entry for
       "ldapserverlist-file will be initialized before this one.  */
@@ -899,6 +1021,21 @@ static gc_option_t gc_options_dirmngr[] =
 
    GC_OPTION_NULL
  };
 
    GC_OPTION_NULL
  };
+#endif /*BUILD_WITH_DIRMNGR*/
+
+
+/* The options of the GC_COMPONENT_PINENTRY component.  */
+static gc_option_t gc_options_pinentry[] =
+ {
+   /* A dummy option to allow gc_component_list_components to find the
+      pinentry backend.  Needs to be a conf file. */
+   { GPGCONF_NAME"-pinentry.conf",
+     GC_OPT_FLAG_NONE, GC_LEVEL_INTERNAL,
+     NULL, NULL, GC_ARG_TYPE_FILENAME, GC_BACKEND_PINENTRY },
+
+   GC_OPTION_NULL
+ };
+
 
 \f
 /* Component system.  Each component is a set of options that can be
 
 \f
 /* Component system.  Each component is a set of options that can be
@@ -921,6 +1058,9 @@ typedef enum
     /* The LDAP Directory Manager for CRLs.  */
     GC_COMPONENT_DIRMNGR,
 
     /* The LDAP Directory Manager for CRLs.  */
     GC_COMPONENT_DIRMNGR,
 
+    /* The external Pinentry.  */
+    GC_COMPONENT_PINENTRY,
+
     /* The number of components.  */
     GC_COMPONENT_NR
   } gc_component_t;
     /* The number of components.  */
     GC_COMPONENT_NR
   } gc_component_t;
@@ -945,11 +1085,12 @@ static struct
   gc_option_t *options;
 } gc_component[] =
   {
   gc_option_t *options;
 } gc_component[] =
   {
-    { "gpg", NULL,   "GPG for OpenPGP", gc_options_gpg },
-    { "gpg-agent", NULL, "GPG Agent", gc_options_gpg_agent },
-    { "scdaemon", NULL, "Smartcard Daemon", gc_options_scdaemon },
-    { "gpgsm", NULL, "GPG for S/MIME", gc_options_gpgsm },
-    { "dirmngr", NULL, "Directory Manager", gc_options_dirmngr }
+    { "gpg",      "gnupg", N_("OpenPGP"), gc_options_gpg },
+    { "gpg-agent","gnupg", N_("Private Keys"), gc_options_gpg_agent },
+    { "scdaemon", "gnupg", N_("Smartcards"), gc_options_scdaemon },
+    { "gpgsm",    "gnupg", N_("S/MIME"), gc_options_gpgsm },
+    { "dirmngr",  "gnupg", N_("Network"), gc_options_dirmngr },
+    { "pinentry", "gnupg", N_("Passphrase Entry"), gc_options_pinentry }
   };
 
 
   };
 
 
@@ -968,65 +1109,326 @@ struct error_line_s
 
 
 \f
 
 
 \f
-/* Engine specific support.  */
+
+/* Initialization and finalization.  */
+
+static void
+gc_option_free (gc_option_t *o)
+{
+  if (o == NULL || o->name == NULL)
+    return;
+
+  xfree (o->value);
+  gc_option_free (o + 1);
+}
+
+static void
+gc_components_free (void)
+{
+  int i;
+  for (i = 0; i < DIM (gc_component); i++)
+    gc_option_free (gc_component[i].options);
+}
+
 void
 void
-gpg_agent_runtime_change (void)
+gc_components_init (void)
+{
+  atexit (gc_components_free);
+}
+
+\f
+
+/* Engine specific support.  */
+static void
+gpg_agent_runtime_change (int killflag)
 {
 {
-#ifndef HAVE_W32_SYSTEM
-  char *agent = getenv ("GPG_AGENT_INFO");
-  char *pid_str;
-  unsigned long pid_long;
-  char *tail;
+  gpg_error_t err = 0;
+  const char *pgmname;
+  const char *argv[5];
+  pid_t pid = (pid_t)(-1);
+  char *abs_homedir = NULL;
+  int i = 0;
+
+  pgmname = gnupg_module_name (GNUPG_MODULE_NAME_CONNECT_AGENT);
+  if (!gnupg_default_homedir_p ())
+    {
+      abs_homedir = make_absfilename_try (gnupg_homedir (), NULL);
+      if (!abs_homedir)
+        err = gpg_error_from_syserror ();
+
+      argv[i++] = "--homedir";
+      argv[i++] = abs_homedir;
+    }
+  argv[i++] = "--no-autostart";
+  argv[i++] = killflag? "KILLAGENT" : "RELOADAGENT";
+  argv[i++] = NULL;
+
+  if (!err)
+    err = gnupg_spawn_process_fd (pgmname, argv, -1, -1, -1, &pid);
+  if (!err)
+    err = gnupg_wait_process (pgmname, pid, 1, NULL);
+  if (err)
+    gc_error (0, 0, "error running '%s %s': %s",
+              pgmname, argv[1], gpg_strerror (err));
+  gnupg_release_process (pid);
+  xfree (abs_homedir);
+}
+
+
+static void
+scdaemon_runtime_change (int killflag)
+{
+  gpg_error_t err = 0;
+  const char *pgmname;
+  const char *argv[9];
+  pid_t pid = (pid_t)(-1);
+  char *abs_homedir = NULL;
+  int i = 0;
+
+  (void)killflag;  /* For scdaemon kill and reload are synonyms.  */
+
+  /* We use "GETINFO app_running" to see whether the agent is already
+     running and kill it only in this case.  This avoids an explicit
+     starting of the agent in case it is not yet running.  There is
+     obviously a race condition but that should not harm too much.  */
+
+  pgmname = gnupg_module_name (GNUPG_MODULE_NAME_CONNECT_AGENT);
+  if (!gnupg_default_homedir_p ())
+    {
+      abs_homedir = make_absfilename_try (gnupg_homedir (), NULL);
+      if (!abs_homedir)
+        err = gpg_error_from_syserror ();
+
+      argv[i++] = "--homedir";
+      argv[i++] = abs_homedir;
+    }
+  argv[i++] = "-s";
+  argv[i++] = "--no-autostart";
+  argv[i++] = "GETINFO scd_running";
+  argv[i++] = "/if ${! $?}";
+  argv[i++] = "scd killscd";
+  argv[i++] = "/end";
+  argv[i++] = NULL;
+
+  if (!err)
+    err = gnupg_spawn_process_fd (pgmname, argv, -1, -1, -1, &pid);
+  if (!err)
+    err = gnupg_wait_process (pgmname, pid, 1, NULL);
+  if (err)
+    gc_error (0, 0, "error running '%s %s': %s",
+              pgmname, argv[4], gpg_strerror (err));
+  gnupg_release_process (pid);
+  xfree (abs_homedir);
+}
+
+
+static void
+dirmngr_runtime_change (int killflag)
+{
+  gpg_error_t err = 0;
+  const char *pgmname;
+  const char *argv[6];
+  pid_t pid = (pid_t)(-1);
+  char *abs_homedir = NULL;
+
+  pgmname = gnupg_module_name (GNUPG_MODULE_NAME_CONNECT_AGENT);
+  argv[0] = "--no-autostart";
+  argv[1] = "--dirmngr";
+  argv[2] = killflag? "KILLDIRMNGR" : "RELOADDIRMNGR";
+  if (gnupg_default_homedir_p ())
+    argv[3] = NULL;
+  else
+    {
+      abs_homedir = make_absfilename_try (gnupg_homedir (), NULL);
+      if (!abs_homedir)
+        err = gpg_error_from_syserror ();
+
+      argv[3] = "--homedir";
+      argv[4] = abs_homedir;
+      argv[5] = NULL;
+    }
+
+  if (!err)
+    err = gnupg_spawn_process_fd (pgmname, argv, -1, -1, -1, &pid);
+  if (!err)
+    err = gnupg_wait_process (pgmname, pid, 1, NULL);
+  if (err)
+    gc_error (0, 0, "error running '%s %s': %s",
+              pgmname, argv[2], gpg_strerror (err));
+  gnupg_release_process (pid);
+  xfree (abs_homedir);
+}
+
+
+/* Launch the gpg-agent or the dirmngr if not already running.  */
+gpg_error_t
+gc_component_launch (int component)
+{
+  gpg_error_t err;
+  const char *pgmname;
+  const char *argv[3];
+  int i;
   pid_t pid;
 
   pid_t pid;
 
-  if (!agent)
-    return;
+  if (component < 0)
+    {
+      err = gc_component_launch (GC_COMPONENT_GPG_AGENT);
+      if (!err)
+        err = gc_component_launch (GC_COMPONENT_DIRMNGR);
+      return err;
+    }
 
 
-  pid_str = strchr (agent, ':');
-  if (!pid_str)
-    return;
+  if (!(component == GC_COMPONENT_GPG_AGENT
+        || component == GC_COMPONENT_DIRMNGR))
+    {
+      es_fputs (_("Component not suitable for launching"), es_stderr);
+      es_putc ('\n', es_stderr);
+      exit (1);
+    }
 
 
-  pid_str++;
-  errno = 0;
-  pid_long = strtoul (pid_str, &tail, 0);
-  if (errno || (*tail != ':' && *tail != '\0'))
-    return;
+  pgmname = gnupg_module_name (GNUPG_MODULE_NAME_CONNECT_AGENT);
+  i = 0;
+  if (component == GC_COMPONENT_DIRMNGR)
+    argv[i++] = "--dirmngr";
+  argv[i++] = "NOP";
+  argv[i] = NULL;
 
 
-  pid = (pid_t) pid_long;
+  err = gnupg_spawn_process_fd (pgmname, argv, -1, -1, -1, &pid);
+  if (!err)
+    err = gnupg_wait_process (pgmname, pid, 1, NULL);
+  if (err)
+    gc_error (0, 0, "error running '%s%s%s': %s",
+              pgmname,
+              component == GC_COMPONENT_DIRMNGR? " --dirmngr":"",
+              " NOP",
+              gpg_strerror (err));
+  gnupg_release_process (pid);
+  return err;
+}
 
 
-  /* Check for overflow.  */
-  if (pid_long != (unsigned long) pid)
-    return;
 
 
-  /* Ignore any errors here.  */
-  kill (pid, SIGHUP);
-#endif /*!HAVE_W32_SYSTEM*/
+/* Unconditionally restart COMPONENT.  */
+void
+gc_component_kill (int component)
+{
+  int runtime[GC_BACKEND_NR];
+  gc_option_t *option;
+  gc_backend_t backend;
+
+  /* Set a flag for the backends to be reloaded.  */
+  for (backend = 0; backend < GC_BACKEND_NR; backend++)
+    runtime[backend] = 0;
+
+  if (component < 0)
+    {
+      for (component = 0; component < GC_COMPONENT_NR; component++)
+        {
+          option = gc_component[component].options;
+          for (; option && option->name; option++)
+            runtime[option->backend] = 1;
+        }
+    }
+  else
+    {
+      assert (component < GC_COMPONENT_NR);
+      option = gc_component[component].options;
+      for (; option && option->name; option++)
+        runtime[option->backend] = 1;
+    }
+
+  /* Do the restart for the selected backends.  */
+  for (backend = 0; backend < GC_BACKEND_NR; backend++)
+    {
+      if (runtime[backend] && gc_backend[backend].runtime_change)
+        (*gc_backend[backend].runtime_change) (1);
+    }
 }
 
 }
 
+
+/* Unconditionally reload COMPONENT or all components if COMPONENT is -1.  */
+void
+gc_component_reload (int component)
+{
+  int runtime[GC_BACKEND_NR];
+  gc_option_t *option;
+  gc_backend_t backend;
+
+  /* Set a flag for the backends to be reloaded.  */
+  for (backend = 0; backend < GC_BACKEND_NR; backend++)
+    runtime[backend] = 0;
+
+  if (component < 0)
+    {
+      for (component = 0; component < GC_COMPONENT_NR; component++)
+        {
+          option = gc_component[component].options;
+          for (; option && option->name; option++)
+            runtime[option->backend] = 1;
+        }
+    }
+  else
+    {
+      assert (component < GC_COMPONENT_NR);
+      option = gc_component[component].options;
+      for (; option && option->name; option++)
+        runtime[option->backend] = 1;
+    }
+
+  /* Do the reload for all selected backends.  */
+  for (backend = 0; backend < GC_BACKEND_NR; backend++)
+    {
+      if (runtime[backend] && gc_backend[backend].runtime_change)
+        (*gc_backend[backend].runtime_change) (0);
+    }
+}
+
+
 \f
 /* More or less Robust version of dgettext.  It has the side effect of
    switching the codeset to utf-8 because this is what we want to
 \f
 /* More or less Robust version of dgettext.  It has the side effect of
    switching the codeset to utf-8 because this is what we want to
-   output.  In theory it is posible to keep the orginal code set and
+   output.  In theory it is posible to keep the original code set and
    switch back for regular disgnostic output (redefine "_(" for that)
    but given the natur of this tool, being something invoked from
    other pograms, it does not make much sense.  */
 static const char *
 my_dgettext (const char *domain, const char *msgid)
 {
    switch back for regular disgnostic output (redefine "_(" for that)
    but given the natur of this tool, being something invoked from
    other pograms, it does not make much sense.  */
 static const char *
 my_dgettext (const char *domain, const char *msgid)
 {
-#ifdef ENABLE_NLS
+#ifdef USE_SIMPLE_GETTEXT
+  if (domain)
+    {
+      static int switched_codeset;
+      char *text;
+
+      if (!switched_codeset)
+        {
+          switched_codeset = 1;
+          gettext_use_utf8 (1);
+        }
+
+      if (!strcmp (domain, "gnupg"))
+        domain = PACKAGE_GT;
+
+      /* FIXME: we have no dgettext, thus we can't switch.  */
+
+      text = (char*)gettext (msgid);
+      return text ? text : msgid;
+    }
+  else
+    return msgid;
+#elif defined(ENABLE_NLS)
   if (domain)
     {
       static int switched_codeset;
       char *text;
   if (domain)
     {
       static int switched_codeset;
       char *text;
-      
+
       if (!switched_codeset)
         {
           switched_codeset = 1;
           bind_textdomain_codeset (PACKAGE_GT, "utf-8");
 
       if (!switched_codeset)
         {
           switched_codeset = 1;
           bind_textdomain_codeset (PACKAGE_GT, "utf-8");
 
-          bindtextdomain ("dirmngr", LOCALEDIR);
-          bind_textdomain_codeset ("dirmngr", "utf-8");
-   
+          bindtextdomain (DIRMNGR_NAME, LOCALEDIR);
+          bind_textdomain_codeset (DIRMNGR_NAME, "utf-8");
+
         }
 
       /* Note: This is a hack to actually use the gnupg2 domain as
         }
 
       /* Note: This is a hack to actually use the gnupg2 domain as
@@ -1039,15 +1441,18 @@ my_dgettext (const char *domain, const char *msgid)
       return text ? text : msgid;
     }
   else
       return text ? text : msgid;
     }
   else
-#endif
     return msgid;
     return msgid;
+#else
+  (void)domain;
+  return msgid;
+#endif
 }
 
 
 /* Percent-Escape special characters.  The string is valid until the
    next invocation of the function.  */
 }
 
 
 /* Percent-Escape special characters.  The string is valid until the
    next invocation of the function.  */
-static char *
-my_percent_escape (const char *src)
+char *
+gc_percent_escape (const char *src)
 {
   static char *esc_str;
   static int esc_str_len;
 {
   static char *esc_str;
   static int esc_str_len;
@@ -1071,7 +1476,7 @@ my_percent_escape (const char *src)
          *(dst++) = '%';
          *(dst++) = '2';
          *(dst++) = '5';
          *(dst++) = '%';
          *(dst++) = '2';
          *(dst++) = '5';
-       }         
+       }
       else if (*src == ':')
        {
          /* The colon is used as field separator.  */
       else if (*src == ':')
        {
          /* The colon is used as field separator.  */
@@ -1086,6 +1491,13 @@ my_percent_escape (const char *src)
          *(dst++) = '2';
          *(dst++) = 'c';
        }
          *(dst++) = '2';
          *(dst++) = 'c';
        }
+      else if (*src == '\n')
+       {
+         /* The newline is problematic in a line-based format.  */
+         *(dst++) = '%';
+         *(dst++) = '0';
+         *(dst++) = 'a';
+       }
       else
        *(dst++) = *(src);
       src++;
       else
        *(dst++) = *(src);
       src++;
@@ -1127,7 +1539,7 @@ percent_deescape (const char *src)
 
          *(dst++) = (char) val;
          src += 3;
 
          *(dst++) = (char) val;
          src += 3;
-       }         
+       }
       else
        *(dst++) = *(src++);
     }
       else
        *(dst++) = *(src++);
     }
@@ -1138,7 +1550,7 @@ percent_deescape (const char *src)
 \f
 /* List all components that are available.  */
 void
 \f
 /* List all components that are available.  */
 void
-gc_component_list_components (FILE *out)
+gc_component_list_components (estream_t out)
 {
   gc_component_t component;
   gc_option_t *option;
 {
   gc_component_t component;
   gc_option_t *option;
@@ -1174,9 +1586,9 @@ gc_component_list_components (FILE *out)
 
           desc = gc_component[component].desc;
           desc = my_dgettext (gc_component[component].desc_domain, desc);
 
           desc = gc_component[component].desc;
           desc = my_dgettext (gc_component[component].desc_domain, desc);
-          fprintf (out, "%s:%s:",
-                   gc_component[component].name,  my_percent_escape (desc));
-          fprintf (out, "%s\n",  my_percent_escape (pgmname));
+          es_fprintf (out, "%s:%s:",
+                      gc_component[component].name,  gc_percent_escape (desc));
+          es_fprintf (out, "%s\n",  gc_percent_escape (pgmname));
         }
     }
 }
         }
     }
 }
@@ -1195,14 +1607,12 @@ all_digits_p (const char *p, size_t len)
 }
 
 
 }
 
 
-/* Collect all error lines from file descriptor FD. Only lines
-   prefixed with TAG are considered.  Close that file descriptor
-   then.  Returns a list of error line items (which may be empty).
-   There is no error return.  */
+/* Collect all error lines from stream FP. Only lines prefixed with
+   TAG are considered.  Returns a list of error line items (which may
+   be empty).  There is no error return.  */
 static error_line_t
 static error_line_t
-collect_error_output (int fd, const char *tag)
+collect_error_output (estream_t fp, const char *tag)
 {
 {
-  FILE *fp;
   char buffer[1024];
   char *p, *p2, *p3;
   int c, cont_line;
   char buffer[1024];
   char *p, *p2, *p3;
   int c, cont_line;
@@ -1210,15 +1620,11 @@ collect_error_output (int fd, const char *tag)
   error_line_t eitem, errlines, *errlines_tail;
   size_t taglen = strlen (tag);
 
   error_line_t eitem, errlines, *errlines_tail;
   size_t taglen = strlen (tag);
 
-  fp = fdopen (fd, "r");
-  if (!fp)
-    gc_error (1, errno, "can't fdopen pipe for reading");
-
   errlines = NULL;
   errlines_tail = &errlines;
   pos = 0;
   cont_line = 0;
   errlines = NULL;
   errlines_tail = &errlines;
   pos = 0;
   cont_line = 0;
-  while ((c=getc (fp)) != EOF)
+  while ((c=es_getc (fp)) != EOF)
     {
       buffer[pos++] = c;
       if (pos >= sizeof buffer - 5 || c == '\n')
     {
       buffer[pos++] = c;
       if (pos >= sizeof buffer - 5 || c == '\n')
@@ -1226,13 +1632,14 @@ collect_error_output (int fd, const char *tag)
           buffer[pos - (c == '\n')] = 0;
           if (cont_line)
             ; /*Ignore continuations of previous line. */
           buffer[pos - (c == '\n')] = 0;
           if (cont_line)
             ; /*Ignore continuations of previous line. */
-          else if (!strncmp (buffer, tag, taglen) && buffer[taglen] == ':') 
+          else if (!strncmp (buffer, tag, taglen) && buffer[taglen] == ':')
             {
               /* "gpgsm: foo:4: bla" */
               /* Yep, we are interested in this line.  */
               p = buffer + taglen + 1;
               while (*p == ' ' || *p == '\t')
                 p++;
             {
               /* "gpgsm: foo:4: bla" */
               /* Yep, we are interested in this line.  */
               p = buffer + taglen + 1;
               while (*p == ' ' || *p == '\t')
                 p++;
+              trim_trailing_spaces (p); /* Get rid of extra CRs.  */
               if (!*p)
                 ; /* Empty lines are ignored.  */
               else if ( (p2 = strchr (p, ':')) && (p3 = strchr (p2+1, ':'))
               if (!*p)
                 ; /* Empty lines are ignored.  */
               else if ( (p2 = strchr (p, ':')) && (p3 = strchr (p2+1, ':'))
@@ -1275,126 +1682,139 @@ collect_error_output (int fd, const char *tag)
           cont_line = (c != '\n');
         }
     }
           cont_line = (c != '\n');
         }
     }
-  
-  /* We ignore error lines not terminated by a LF.  */
 
 
-  fclose (fp);
+  /* We ignore error lines not terminated by a LF.  */
   return errlines;
 }
 
 
   return errlines;
 }
 
 
-
-/* Check all components that are available.  */
-void
-gc_component_check_programs (FILE *out)
+/* Check the options of a single component.  Returns 0 if everything
+   is OK.  */
+int
+gc_component_check_options (int component, estream_t out, const char *conf_file)
 {
   gpg_error_t err;
 {
   gpg_error_t err;
-  gc_component_t component;
   unsigned int result;
   int backend_seen[GC_BACKEND_NR];
   gc_backend_t backend;
   gc_option_t *option;
   unsigned int result;
   int backend_seen[GC_BACKEND_NR];
   gc_backend_t backend;
   gc_option_t *option;
-  const char *desc;
   const char *pgmname;
   const char *pgmname;
-  const char *argv[2];
+  const char *argv[4];
+  int i;
   pid_t pid;
   int exitcode;
   pid_t pid;
   int exitcode;
-  int filedes[2];
-  error_line_t errlines, errptr;
+  estream_t errfp;
+  error_line_t errlines;
 
 
-  /* We use a temporary file to collect the error output.  It would be
-     better to use a pipe here but as of now we have no suitable
-     fucntion to create a portable pipe outside of exechelp.  Thus it
-     is easier to use the tempfile approach.  */
-  for (component = 0; component < GC_COMPONENT_NR; component++)
+  for (backend = 0; backend < GC_BACKEND_NR; backend++)
+    backend_seen[backend] = 0;
+
+  option = gc_component[component].options;
+  for (; option && option->name; option++)
     {
     {
-      if (!gc_component[component].options)
-        continue;
+      if ((option->flags & GC_OPT_FLAG_GROUP))
+       continue;
+      backend = option->backend;
+      if (backend_seen[backend])
+       continue;
+      backend_seen[backend] = 1;
+      assert (backend != GC_BACKEND_ANY);
+      if (!gc_backend[backend].program)
+       continue;
+      if (!gc_backend[backend].module_name)
+       continue;
+
+      break;
+    }
+  if (! option || ! option->name)
+    return 0;
 
 
-      for (backend = 0; backend < GC_BACKEND_NR; backend++)
-        backend_seen[backend] = 0;
+  pgmname = gnupg_module_name (gc_backend[backend].module_name);
+  i = 0;
+  if (conf_file)
+    {
+      argv[i++] = "--options";
+      argv[i++] = conf_file;
+    }
+  if (component == GC_COMPONENT_PINENTRY)
+    argv[i++] = "--version";
+  else
+    argv[i++] = "--gpgconf-test";
+  argv[i++] = NULL;
 
 
-      option = gc_component[component].options;
-      for (; option && option->name; option++)
-        {
-          if ((option->flags & GC_OPT_FLAG_GROUP))
-            continue;
-          backend = option->backend;
-          if (backend_seen[backend])
-            continue;
-          backend_seen[backend] = 1;
-          assert (backend != GC_BACKEND_ANY);
-          if (!gc_backend[backend].program)
-            continue;
-          if (!gc_backend[backend].module_name)
-            continue;
-
-          pgmname = gnupg_module_name (gc_backend[backend].module_name);
-          argv[0] = "--gpgconf-test";
-          argv[1] = NULL;
-
-          err = gnupg_create_inbound_pipe (filedes);
-          if (err)
-            gc_error (1, 0, _("error creating a pipe: %s\n"), 
-                      gpg_strerror (err));
-
-          result = 0;
-          errlines = NULL;
-          if (gnupg_spawn_process_fd (pgmname, argv, -1, -1, filedes[1], &pid))
-            {
-              close (filedes[0]);
-              close (filedes[1]);
-              result |= 1; /* Program could not be run.  */
-            }
-          else 
-            {
-              close (filedes[1]);
-              errlines = collect_error_output (filedes[0], 
-                                               gc_component[component].name);
-              if (gnupg_wait_process (pgmname, pid, &exitcode))
-                {
-                  if (exitcode == -1)
-                    result |= 1; /* Program could not be run or it
-                                    terminated abnormally.  */
-                  result |= 2; /* Program returned an error.  */
-                }
-            }
-          
-          /* If the program could not be run, we can't tell whether
-             the config file is good.  */
-          if ((result&1))
-            result |= 2;  
-          
-          desc = gc_component[component].desc;
-          desc = my_dgettext (gc_component[component].desc_domain, desc);
-          fprintf (out, "%s:%s:",
-                   gc_component[component].name, my_percent_escape (desc));
-          fputs (my_percent_escape (pgmname), out);
-          fprintf (out, ":%d:%d:", !(result & 1), !(result & 2));
-          for (errptr = errlines; errptr; errptr = errptr->next)
-            {
-              if (errptr != errlines)
-                fputs ("\n:::::", out); /* Continuation line.  */
-              if (errptr->fname)
-                fputs (my_percent_escape (errptr->fname), out);
-              putc (':', out);
-              if (errptr->fname)
-                fprintf (out, "%u", errptr->lineno);
-              putc (':', out);
-              fputs (my_percent_escape (errptr->errtext), out);
-              putc (':', out);
-            }
-          putc ('\n', out);
-          
-          while (errlines)
-            {
-              error_line_t tmp = errlines->next;
-              xfree (errlines);
-              errlines = tmp;
-            }
-          break; /* Loop over options of this component  */
-        }
-    } 
+  result = 0;
+  errlines = NULL;
+  err = gnupg_spawn_process (pgmname, argv, NULL, NULL, 0,
+                             NULL, NULL, &errfp, &pid);
+  if (err)
+    result |= 1; /* Program could not be run.  */
+  else
+    {
+      errlines = collect_error_output (errfp,
+                                      gc_component[component].name);
+      if (gnupg_wait_process (pgmname, pid, 1, &exitcode))
+       {
+         if (exitcode == -1)
+           result |= 1; /* Program could not be run or it
+                           terminated abnormally.  */
+         result |= 2; /* Program returned an error.  */
+       }
+      gnupg_release_process (pid);
+      es_fclose (errfp);
+    }
+
+  /* If the program could not be run, we can't tell whether
+     the config file is good.  */
+  if (result & 1)
+    result |= 2;
+
+  if (out)
+    {
+      const char *desc;
+      error_line_t errptr;
+
+      desc = gc_component[component].desc;
+      desc = my_dgettext (gc_component[component].desc_domain, desc);
+      es_fprintf (out, "%s:%s:",
+                  gc_component[component].name, gc_percent_escape (desc));
+      es_fputs (gc_percent_escape (pgmname), out);
+      es_fprintf (out, ":%d:%d:", !(result & 1), !(result & 2));
+      for (errptr = errlines; errptr; errptr = errptr->next)
+       {
+         if (errptr != errlines)
+           es_fputs ("\n:::::", out); /* Continuation line.  */
+         if (errptr->fname)
+           es_fputs (gc_percent_escape (errptr->fname), out);
+         es_putc (':', out);
+         if (errptr->fname)
+           es_fprintf (out, "%u", errptr->lineno);
+         es_putc (':', out);
+         es_fputs (gc_percent_escape (errptr->errtext), out);
+         es_putc (':', out);
+       }
+      es_putc ('\n', out);
+    }
+
+  while (errlines)
+    {
+      error_line_t tmp = errlines->next;
+      xfree (errlines);
+      errlines = tmp;
+    }
+
+  return result;
+}
+
+
+
+/* Check all components that are available.  */
+void
+gc_check_programs (estream_t out)
+{
+  gc_component_t component;
+
+  for (component = 0; component < GC_COMPONENT_NR; component++)
+    gc_component_check_options (component, out, NULL);
 }
 
 
 }
 
 
@@ -1418,7 +1838,7 @@ gc_component_find (const char *name)
 \f
 /* List the option OPTION.  */
 static void
 \f
 /* List the option OPTION.  */
 static void
-list_one_option (const gc_option_t *option, FILE *out)
+list_one_option (const gc_option_t *option, estream_t out)
 {
   const char *desc = NULL;
   char *arg_name = NULL;
 {
   const char *desc = NULL;
   char *arg_name = NULL;
@@ -1448,16 +1868,16 @@ list_one_option (const gc_option_t *option, FILE *out)
      FIELDS.  */
 
   /* The name field.  */
      FIELDS.  */
 
   /* The name field.  */
-  fprintf (out, "%s", option->name);
+  es_fprintf (out, "%s", option->name);
 
   /* The flags field.  */
 
   /* The flags field.  */
-  fprintf (out, ":%lu", option->flags);
+  es_fprintf (out, ":%lu", option->flags);
   if (opt.verbose)
     {
   if (opt.verbose)
     {
-      putc (' ', out);
-         
+      es_putc (' ', out);
+
       if (!option->flags)
       if (!option->flags)
-       fprintf (out, "none");
+       es_fprintf (out, "none");
       else
        {
          unsigned long flags = option->flags;
       else
        {
          unsigned long flags = option->flags;
@@ -1471,8 +1891,8 @@ list_one_option (const gc_option_t *option, FILE *out)
                  if (first)
                    first = 0;
                  else
                  if (first)
                    first = 0;
                  else
-                   putc (',', out);
-                 fprintf (out, "%s", gc_flag[flag].name);
+                   es_putc (',', out);
+                 es_fprintf (out, "%s", gc_flag[flag].name);
                }
              flags >>= 1;
              flag++;
                }
              flags >>= 1;
              flag++;
@@ -1481,34 +1901,33 @@ list_one_option (const gc_option_t *option, FILE *out)
     }
 
   /* The level field.  */
     }
 
   /* The level field.  */
-  fprintf (out, ":%u", option->level);
+  es_fprintf (out, ":%u", option->level);
   if (opt.verbose)
   if (opt.verbose)
-    fprintf (out, " %s", gc_level[option->level].name);
+    es_fprintf (out, " %s", gc_level[option->level].name);
 
   /* The description field.  */
 
   /* The description field.  */
-  fprintf (out, ":%s", desc ? my_percent_escape (desc) : "");
-  
+  es_fprintf (out, ":%s", desc ? gc_percent_escape (desc) : "");
+
   /* The type field.  */
   /* The type field.  */
-  fprintf (out, ":%u", option->arg_type);
+  es_fprintf (out, ":%u", option->arg_type);
   if (opt.verbose)
   if (opt.verbose)
-    fprintf (out, " %s", gc_arg_type[option->arg_type].name);
+    es_fprintf (out, " %s", gc_arg_type[option->arg_type].name);
 
   /* The alternate type field.  */
 
   /* The alternate type field.  */
-  fprintf (out, ":%u", gc_arg_type[option->arg_type].fallback);
+  es_fprintf (out, ":%u", gc_arg_type[option->arg_type].fallback);
   if (opt.verbose)
   if (opt.verbose)
-    fprintf (out, " %s",
-            gc_arg_type[gc_arg_type[option->arg_type].fallback].name);
+    es_fprintf (out, " %s",
+                gc_arg_type[gc_arg_type[option->arg_type].fallback].name);
 
   /* The argument name field.  */
 
   /* The argument name field.  */
-  fprintf (out, ":%s", arg_name ? my_percent_escape (arg_name) : "");
-  if (arg_name)
-    xfree (arg_name);
+  es_fprintf (out, ":%s", arg_name ? gc_percent_escape (arg_name) : "");
+  xfree (arg_name);
 
   /* The default value field.  */
 
   /* The default value field.  */
-  fprintf (out, ":%s", option->default_value ? option->default_value : "");
+  es_fprintf (out, ":%s", option->default_value ? option->default_value : "");
 
   /* The default argument field.  */
 
   /* The default argument field.  */
-  fprintf (out, ":%s", option->default_arg ? option->default_arg : "");
+  es_fprintf (out, ":%s", option->default_arg ? option->default_arg : "");
 
   /* The value field.  */
   if (gc_arg_type[option->arg_type].fallback == GC_ARG_TYPE_NONE
 
   /* The value field.  */
   if (gc_arg_type[option->arg_type].fallback == GC_ARG_TYPE_NONE
@@ -1516,20 +1935,20 @@ list_one_option (const gc_option_t *option, FILE *out)
       && option->value)
     /* The special format "1,1,1,1,...,1" is converted to a number
        here.  */
       && option->value)
     /* The special format "1,1,1,1,...,1" is converted to a number
        here.  */
-    fprintf (out, ":%u", (unsigned int)((strlen (option->value) + 1) / 2));
+    es_fprintf (out, ":%u", (unsigned int)((strlen (option->value) + 1) / 2));
   else
   else
-    fprintf (out, ":%s", option->value ? option->value : "");
+    es_fprintf (out, ":%s", option->value ? option->value : "");
 
   /* ADD NEW FIELDS HERE.  */
 
 
   /* ADD NEW FIELDS HERE.  */
 
-  putc ('\n', out);
+  es_putc ('\n', out);
 }
 
 
 /* List all options of the component COMPONENT.  */
 void
 }
 
 
 /* List all options of the component COMPONENT.  */
 void
-gc_component_list_options (int component, FILE *out)
-{  
+gc_component_list_options (int component, estream_t out)
+{
   const gc_option_t *option = gc_component[component].options;
 
   while (option && option->name)
   const gc_option_t *option = gc_component[component].options;
 
   while (option && option->name)
@@ -1552,7 +1971,7 @@ gc_component_list_options (int component, FILE *out)
             different active options, and because it is hard to
             maintain manually, we calculate it here.  The value in
             the global static table is ignored.  */
             different active options, and because it is hard to
             maintain manually, we calculate it here.  The value in
             the global static table is ignored.  */
-         
+
          while (group_option->name)
            {
              if (group_option->flags & GC_OPT_FLAG_GROUP)
          while (group_option->name)
            {
              if (group_option->flags & GC_OPT_FLAG_GROUP)
@@ -1568,7 +1987,7 @@ gc_component_list_options (int component, FILE *out)
              gc_option_t opt_copy;
 
              /* Fix up the group level.  */
              gc_option_t opt_copy;
 
              /* Fix up the group level.  */
-             memcpy (&opt_copy, option, sizeof (opt));
+             memcpy (&opt_copy, option, sizeof (opt_copy));
              opt_copy.level = level;
              list_one_option (&opt_copy, out);
            }
              opt_copy.level = level;
              list_one_option (&opt_copy, out);
            }
@@ -1600,16 +2019,16 @@ find_option (gc_component_t component, const char *name,
 }
 
 \f
 }
 
 \f
-/* Determine the configuration pathname for the component COMPONENT
+/* Determine the configuration filename for the component COMPONENT
    and backend BACKEND.  */
 static char *
    and backend BACKEND.  */
 static char *
-get_config_pathname (gc_component_t component, gc_backend_t backend)
+get_config_filename (gc_component_t component, gc_backend_t backend)
 {
 {
-  char *pathname = NULL;
+  char *filename = NULL;
   gc_option_t *option = find_option
     (component, gc_backend[backend].option_config_filename, GC_BACKEND_ANY);
   assert (option);
   gc_option_t *option = find_option
     (component, gc_backend[backend].option_config_filename, GC_BACKEND_ANY);
   assert (option);
-  assert (option->arg_type == GC_ARG_TYPE_PATHNAME);
+  assert (option->arg_type == GC_ARG_TYPE_FILENAME);
   assert (!(option->flags & GC_OPT_FLAG_LIST));
 
   if (!option->active || !option->default_value)
   assert (!(option->flags & GC_OPT_FLAG_LIST));
 
   if (!option->active || !option->default_value)
@@ -1618,24 +2037,26 @@ get_config_pathname (gc_component_t component, gc_backend_t backend)
              gc_backend[backend].name);
 
   if (option->value && *option->value)
              gc_backend[backend].name);
 
   if (option->value && *option->value)
-    pathname = percent_deescape (&option->value[1]);
+    filename = percent_deescape (&option->value[1]);
   else if (option->default_value && *option->default_value)
   else if (option->default_value && *option->default_value)
-    pathname = percent_deescape (&option->default_value[1]);
+    filename = percent_deescape (&option->default_value[1]);
   else
   else
-    pathname = "";
-
-#ifdef HAVE_DOSISH_SYSTEM
-  if (!(pathname[0] 
-        && pathname[1] == ':'
-        && (pathname[2] == '/' || pathname[2] == '\\')))
+    filename = "";
+
+#if HAVE_W32CE_SYSTEM
+  if (!(filename[0] == '/' || filename[0] == '\\'))
+#elif defined(HAVE_DOSISH_SYSTEM)
+  if (!(filename[0]
+        && filename[1] == ':'
+        && (filename[2] == '/' || filename[2] == '\\')))
 #else
 #else
-  if (pathname[0] != '/')
+  if (filename[0] != '/')
 #endif
     gc_error (1, 0, "Option %s, needed by backend %s, is not absolute",
              gc_backend[backend].option_config_filename,
              gc_backend[backend].name);
 
 #endif
     gc_error (1, 0, "Option %s, needed by backend %s, is not absolute",
              gc_backend[backend].option_config_filename,
              gc_backend[backend].name);
 
-  return pathname;
+  return filename;
 }
 
 \f
 }
 
 \f
@@ -1645,47 +2066,38 @@ static void
 retrieve_options_from_program (gc_component_t component, gc_backend_t backend)
 {
   gpg_error_t err;
 retrieve_options_from_program (gc_component_t component, gc_backend_t backend)
 {
   gpg_error_t err;
-  int filedes[2];
   const char *pgmname;
   const char *argv[2];
   const char *pgmname;
   const char *argv[2];
+  estream_t outfp;
   int exitcode;
   pid_t pid;
   char *line = NULL;
   size_t line_len = 0;
   ssize_t length;
   int exitcode;
   pid_t pid;
   char *line = NULL;
   size_t line_len = 0;
   ssize_t length;
-  FILE *config;
-  char *config_pathname;
-
-  err = gnupg_create_inbound_pipe (filedes);
-  if (err)
-    gc_error (1, 0, _("error creating a pipe: %s\n"), gpg_strerror (err));
+  estream_t config;
+  char *config_filename;
 
 
-  pgmname = (gc_backend[backend].module_name 
-             ? gnupg_module_name (gc_backend[backend].module_name) 
+  pgmname = (gc_backend[backend].module_name
+             ? gnupg_module_name (gc_backend[backend].module_name)
              : gc_backend[backend].program );
   argv[0] = "--gpgconf-list";
   argv[1] = NULL;
 
              : gc_backend[backend].program );
   argv[0] = "--gpgconf-list";
   argv[1] = NULL;
 
-  err = gnupg_spawn_process_fd (pgmname, argv, -1, filedes[1], -1, &pid);
+  err = gnupg_spawn_process (pgmname, argv, NULL, NULL, 0,
+                             NULL, &outfp, NULL, &pid);
   if (err)
     {
   if (err)
     {
-      close (filedes[0]);
-      close (filedes[1]);
-      gc_error (1, 0, "could not gather active options from `%s': %s",
+      gc_error (1, 0, "could not gather active options from '%s': %s",
                 pgmname, gpg_strerror (err));
     }
                 pgmname, gpg_strerror (err));
     }
-  close (filedes[1]);
-  config = fdopen (filedes[0], "r");
-  if (!config)
-    gc_error (1, errno, "can't fdopen pipe for reading");
 
 
-  while ((length = read_line (config, &line, &line_len, NULL)) > 0)
+  while ((length = es_read_line (outfp, &line, &line_len, NULL)) > 0)
     {
       gc_option_t *option;
       char *linep;
       unsigned long flags = 0;
       char *default_value = NULL;
     {
       gc_option_t *option;
       char *linep;
       unsigned long flags = 0;
       char *default_value = NULL;
-      
+
       /* Strip newline and carriage return, if present.  */
       while (length > 0
             && (line[length - 1] == '\n' || line[length - 1] == '\r'))
       /* Strip newline and carriage return, if present.  */
       while (length > 0
             && (line[length - 1] == '\n' || line[length - 1] == '\r'))
@@ -1694,7 +2106,7 @@ retrieve_options_from_program (gc_component_t component, gc_backend_t backend)
       linep = strchr (line, ':');
       if (linep)
        *(linep++) = '\0';
       linep = strchr (line, ':');
       if (linep)
        *(linep++) = '\0';
-      
+
       /* Extract additional flags.  Default to none.  */
       if (linep)
        {
       /* Extract additional flags.  Default to none.  */
       if (linep)
        {
@@ -1705,7 +2117,7 @@ retrieve_options_from_program (gc_component_t component, gc_backend_t backend)
          if (end)
            *(end++) = '\0';
 
          if (end)
            *(end++) = '\0';
 
-         errno = 0;
+         gpg_err_set_errno (0);
          flags = strtoul (linep, &tail, 0);
          if (errno)
            gc_error (1, errno, "malformed flags in option %s from %s",
          flags = strtoul (linep, &tail, 0);
          if (errno)
            gc_error (1, errno, "malformed flags in option %s from %s",
@@ -1748,32 +2160,36 @@ retrieve_options_from_program (gc_component_t component, gc_backend_t backend)
            option->default_value = xstrdup (default_value);
        }
     }
            option->default_value = xstrdup (default_value);
        }
     }
-  if (length < 0 || ferror (config))
-    gc_error (1, errno, "error reading from %s",pgmname);
-  if (fclose (config) && ferror (config))
+  if (length < 0 || es_ferror (outfp))
+    gc_error (1, errno, "error reading from %s", pgmname);
+  if (es_fclose (outfp))
     gc_error (1, errno, "error closing %s", pgmname);
 
     gc_error (1, errno, "error closing %s", pgmname);
 
-  err = gnupg_wait_process (pgmname, pid, &exitcode);
+  err = gnupg_wait_process (pgmname, pid, 1, &exitcode);
   if (err)
     gc_error (1, 0, "running %s failed (exitcode=%d): %s",
               pgmname, exitcode, gpg_strerror (err));
   if (err)
     gc_error (1, 0, "running %s failed (exitcode=%d): %s",
               pgmname, exitcode, gpg_strerror (err));
+  gnupg_release_process (pid);
 
 
   /* At this point, we can parse the configuration file.  */
 
 
   /* At this point, we can parse the configuration file.  */
-  config_pathname = get_config_pathname (component, backend);
+  config_filename = get_config_filename (component, backend);
 
 
-  config = fopen (config_pathname, "r");
+  config = es_fopen (config_filename, "r");
   if (!config)
   if (!config)
-    gc_error (0, errno, "warning: can not open config file %s",
-             config_pathname);
+    {
+      if (errno != ENOENT)
+        gc_error (0, errno, "warning: can not open config file %s",
+                  config_filename);
+    }
   else
     {
   else
     {
-      while ((length = read_line (config, &line, &line_len, NULL)) > 0)
+      while ((length = es_read_line (config, &line, &line_len, NULL)) > 0)
        {
          char *name;
          char *value;
          gc_option_t *option;
        {
          char *name;
          char *value;
          gc_option_t *option;
-         
+
          name = line;
          while (*name == ' ' || *name == '\t')
            name++;
          name = line;
          while (*name == ' ' || *name == '\t')
            name++;
@@ -1819,7 +2235,7 @@ retrieve_options_from_program (gc_component_t component, gc_backend_t backend)
                }
              else if (gc_arg_type[option->arg_type].fallback
                       == GC_ARG_TYPE_STRING)
                }
              else if (gc_arg_type[option->arg_type].fallback
                       == GC_ARG_TYPE_STRING)
-               opt_value = xasprintf ("\"%s", my_percent_escape (value));
+               opt_value = xasprintf ("\"%s", gc_percent_escape (value));
              else
                {
                  /* FIXME: Verify that the number is sane.  */
              else
                {
                  /* FIXME: Verify that the number is sane.  */
@@ -1830,7 +2246,7 @@ retrieve_options_from_program (gc_component_t component, gc_backend_t backend)
              if (!(option->flags & GC_OPT_FLAG_LIST))
                {
                  if (option->value)
              if (!(option->flags & GC_OPT_FLAG_LIST))
                {
                  if (option->value)
-                   free (option->value);
+                   xfree (option->value);
                  option->value = opt_value;
                }
              else
                  option->value = opt_value;
                }
              else
@@ -1839,20 +2255,19 @@ retrieve_options_from_program (gc_component_t component, gc_backend_t backend)
                    option->value = opt_value;
                  else
                    {
                    option->value = opt_value;
                  else
                    {
-                     char *opt_val = opt_value;
-
-                     option->value = xasprintf ("%s,%s", option->value,
-                                                opt_val);
+                     char *old = option->value;
+                     option->value = xasprintf ("%s,%s", old, opt_value);
+                     xfree (old);
                      xfree (opt_value);
                    }
                }
            }
        }
 
                      xfree (opt_value);
                    }
                }
            }
        }
 
-      if (length < 0 || ferror (config))
-       gc_error (1, errno, "error reading from %s", config_pathname);
-      if (fclose (config) && ferror (config))
-       gc_error (1, errno, "error closing %s", config_pathname);
+      if (length < 0 || es_ferror (config))
+       gc_error (1, errno, "error reading from %s", config_filename);
+      if (es_fclose (config))
+       gc_error (1, errno, "error closing %s", config_filename);
     }
 
   xfree (line);
     }
 
   xfree (line);
@@ -1860,13 +2275,14 @@ retrieve_options_from_program (gc_component_t component, gc_backend_t backend)
 
 
 /* Retrieve the options for the component COMPONENT from backend
 
 
 /* Retrieve the options for the component COMPONENT from backend
-   BACKEND, which we already know is of type file list.  */ 
+   BACKEND, which we already know is of type file list.  */
 static void
 retrieve_options_from_file (gc_component_t component, gc_backend_t backend)
 {
   gc_option_t *list_option;
 static void
 retrieve_options_from_file (gc_component_t component, gc_backend_t backend)
 {
   gc_option_t *list_option;
-  char *list_pathname;
-  FILE *list_file;
+  gc_option_t *config_option;
+  char *list_filename;
+  gpgrt_stream_t list_file;
   char *line = NULL;
   size_t line_len = 0;
   ssize_t length;
   char *line = NULL;
   size_t line_len = 0;
   ssize_t length;
@@ -1877,14 +2293,14 @@ retrieve_options_from_file (gc_component_t component, gc_backend_t backend)
   assert (list_option);
   assert (!list_option->active);
 
   assert (list_option);
   assert (!list_option->active);
 
-  list_pathname = get_config_pathname (component, backend);
-  list_file = fopen (list_pathname, "r");
+  list_filename = get_config_filename (component, backend);
+  list_file = gpgrt_fopen (list_filename, "r");
   if (!list_file)
   if (!list_file)
-    gc_error (0, errno, "warning: can not open list file %s", list_pathname);
+    gc_error (0, errno, "warning: can not open list file %s", list_filename);
   else
     {
 
   else
     {
 
-      while ((length = read_line (list_file, &line, &line_len, NULL)) > 0)
+      while ((length = gpgrt_read_line (list_file, &line, &line_len, NULL)) > 0)
        {
          char *start;
          char *end;
        {
          char *start;
          char *end;
@@ -1910,22 +2326,28 @@ retrieve_options_from_file (gc_component_t component, gc_backend_t backend)
             really append.  */
          if (list)
            {
             really append.  */
          if (list)
            {
-             new_list = xasprintf ("%s,\"%s", list, my_percent_escape (start));
+             new_list = xasprintf ("%s,\"%s", list, gc_percent_escape (start));
              xfree (list);
              list = new_list;
            }
          else
              xfree (list);
              list = new_list;
            }
          else
-           list = xasprintf ("\"%s", my_percent_escape (start));
+           list = xasprintf ("\"%s", gc_percent_escape (start));
        }
        }
-      if (length < 0 || ferror (list_file))
-       gc_error (1, errno, "can not read list file %s", list_pathname);
+      if (length < 0 || gpgrt_ferror (list_file))
+       gc_error (1, errno, "can not read list file %s", list_filename);
     }
 
   list_option->active = 1;
   list_option->value = list;
 
     }
 
   list_option->active = 1;
   list_option->value = list;
 
-  if (list_file && fclose (list_file) && ferror (list_file))
-    gc_error (1, errno, "error closing %s", list_pathname);
+  /* Fix up the read-only flag.  */
+  config_option = find_option
+    (component, gc_backend[backend].option_config_filename, GC_BACKEND_ANY);
+  if (config_option->flags & GC_OPT_FLAG_NO_CHANGE)
+    list_option->flags |= GC_OPT_FLAG_NO_CHANGE;
+
+  if (list_file && gpgrt_fclose (list_file))
+    gc_error (1, errno, "error closing %s", list_filename);
   xfree (line);
 }
 
   xfree (line);
 }
 
@@ -1950,9 +2372,12 @@ gc_component_retrieve_options (int component)
       component = 0;
       assert (component < GC_COMPONENT_NR);
     }
       component = 0;
       assert (component < GC_COMPONENT_NR);
     }
-      
+
   do
     {
   do
     {
+      if (component == GC_COMPONENT_PINENTRY)
+        continue; /* Skip this dummy component.  */
+
       option = gc_component[component].options;
 
       while (option && option->name)
       option = gc_component[component].options;
 
       while (option && option->name)
@@ -1960,16 +2385,16 @@ gc_component_retrieve_options (int component)
           if (!(option->flags & GC_OPT_FLAG_GROUP))
             {
               backend = option->backend;
           if (!(option->flags & GC_OPT_FLAG_GROUP))
             {
               backend = option->backend;
-              
+
               if (backend_seen[backend])
                 {
                   option++;
                   continue;
                 }
               backend_seen[backend] = 1;
               if (backend_seen[backend])
                 {
                   option++;
                   continue;
                 }
               backend_seen[backend] = 1;
-              
+
               assert (backend != GC_BACKEND_ANY);
               assert (backend != GC_BACKEND_ANY);
-              
+
               if (gc_backend[backend].program)
                 retrieve_options_from_program (component, backend);
               else
               if (gc_backend[backend].program)
                 retrieve_options_from_program (component, backend);
               else
@@ -1985,18 +2410,20 @@ gc_component_retrieve_options (int component)
 
 \f
 /* Perform a simple validity check based on the type.  Return in
 
 \f
 /* Perform a simple validity check based on the type.  Return in
-   NEW_VALUE_NR the value of the number in NEW_VALUE if OPTION is of
-   type GC_ARG_TYPE_NONE.  */
+ * NEW_VALUE_NR the value of the number in NEW_VALUE if OPTION is of
+ * type GC_ARG_TYPE_NONE.  If VERBATIM is set the profile parsing mode
+ * is used. */
 static void
 option_check_validity (gc_option_t *option, unsigned long flags,
 static void
 option_check_validity (gc_option_t *option, unsigned long flags,
-                      char *new_value, unsigned long *new_value_nr)
+                      char *new_value, unsigned long *new_value_nr,
+                       int verbatim)
 {
   char *arg;
 
   if (!option->active)
     gc_error (1, 0, "option %s not supported by backend %s",
               option->name, gc_backend[option->backend].name);
 {
   char *arg;
 
   if (!option->active)
     gc_error (1, 0, "option %s not supported by backend %s",
               option->name, gc_backend[option->backend].name);
-      
+
   if (option->new_flags || option->new_value)
     gc_error (1, 0, "option %s already changed", option->name);
 
   if (option->new_flags || option->new_value)
     gc_error (1, 0, "option %s already changed", option->name);
 
@@ -2014,7 +2441,7 @@ option_check_validity (gc_option_t *option, unsigned long flags,
     {
       char *tail;
 
     {
       char *tail;
 
-      errno = 0;
+      gpg_err_set_errno (0);
       *new_value_nr = strtoul (new_value, &tail, 0);
 
       if (errno)
       *new_value_nr = strtoul (new_value, &tail, 0);
 
       if (errno)
@@ -2043,47 +2470,62 @@ option_check_validity (gc_option_t *option, unsigned long flags,
   arg = new_value;
   do
     {
   arg = new_value;
   do
     {
-      if (*arg == '\0' || *arg == ',')
+      if (*arg == '\0' || (*arg == ',' && !verbatim))
        {
          if (!(option->flags & GC_OPT_FLAG_ARG_OPT))
            gc_error (1, 0, "argument required for option %s", option->name);
 
        {
          if (!(option->flags & GC_OPT_FLAG_ARG_OPT))
            gc_error (1, 0, "argument required for option %s", option->name);
 
-         if (*arg == ',' && !(option->flags & GC_OPT_FLAG_LIST))
+         if (*arg == ',' && !verbatim && !(option->flags & GC_OPT_FLAG_LIST))
            gc_error (1, 0, "list found for non-list option %s", option->name);
        }
       else if (gc_arg_type[option->arg_type].fallback == GC_ARG_TYPE_STRING)
        {
            gc_error (1, 0, "list found for non-list option %s", option->name);
        }
       else if (gc_arg_type[option->arg_type].fallback == GC_ARG_TYPE_STRING)
        {
-         if (*arg != '"')
+         if (*arg != '"' && !verbatim)
            gc_error (1, 0, "string argument for option %s must begin "
                      "with a quote (\") character", option->name);
            gc_error (1, 0, "string argument for option %s must begin "
                      "with a quote (\") character", option->name);
+
+         /* FIXME: We do not allow empty string arguments for now, as
+            we do not quote arguments in configuration files, and
+            thus no argument is indistinguishable from the empty
+            string.  */
+         if (arg[1] == '\0' || (arg[1] == ',' && !verbatim))
+           gc_error (1, 0, "empty string argument for option %s is "
+                     "currently not allowed.  Please report this!",
+                     option->name);
        }
       else if (gc_arg_type[option->arg_type].fallback == GC_ARG_TYPE_INT32)
        {
        }
       else if (gc_arg_type[option->arg_type].fallback == GC_ARG_TYPE_INT32)
        {
-         errno = 0;
-         (void) strtol (arg, &arg, 0);
+         long res;
+
+         gpg_err_set_errno (0);
+         res = strtol (arg, &arg, 0);
+         (void) res;
 
          if (errno)
            gc_error (1, errno, "invalid argument for option %s",
                      option->name);
 
 
          if (errno)
            gc_error (1, errno, "invalid argument for option %s",
                      option->name);
 
-         if (*arg != '\0' && *arg != ',')
+         if (*arg != '\0' && (*arg != ',' || verbatim))
            gc_error (1, 0, "garbage after argument for option %s",
                      option->name);
        }
            gc_error (1, 0, "garbage after argument for option %s",
                      option->name);
        }
-      else if (gc_arg_type[option->arg_type].fallback == GC_ARG_TYPE_INT32)
+      else if (gc_arg_type[option->arg_type].fallback == GC_ARG_TYPE_UINT32)
        {
        {
-         errno = 0;
-         (void) strtoul (arg, &arg, 0);
+         unsigned long res;
+
+         gpg_err_set_errno (0);
+         res = strtoul (arg, &arg, 0);
+         (void) res;
 
          if (errno)
            gc_error (1, errno, "invalid argument for option %s",
                      option->name);
 
 
          if (errno)
            gc_error (1, errno, "invalid argument for option %s",
                      option->name);
 
-         if (*arg != '\0' && *arg != ',')
+         if (*arg != '\0' && (*arg != ',' || verbatim))
            gc_error (1, 0, "garbage after argument for option %s",
                      option->name);
        }
            gc_error (1, 0, "garbage after argument for option %s",
                      option->name);
        }
-      arg = strchr (arg, ',');
+      arg = verbatim? strchr (arg, ',') : NULL;
       if (arg)
        arg++;
     }
       if (arg)
        arg++;
     }
@@ -2097,19 +2539,19 @@ copy_file (const char *src_name, const char *dst_name)
 #define BUF_LEN 4096
   char buffer[BUF_LEN];
   int len;
 #define BUF_LEN 4096
   char buffer[BUF_LEN];
   int len;
-  FILE *src;
-  FILE *dst;
+  gpgrt_stream_t src;
+  gpgrt_stream_t dst;
 
 
-  src = fopen (src_name, "r");
+  src = gpgrt_fopen (src_name, "r");
   if (src == NULL)
     return -1;
 
   if (src == NULL)
     return -1;
 
-  dst = fopen (dst_name, "w");
+  dst = gpgrt_fopen (dst_name, "w");
   if (dst == NULL)
     {
       int saved_err = errno;
   if (dst == NULL)
     {
       int saved_err = errno;
-      fclose (src);
-      errno = saved_err;
+      gpgrt_fclose (src);
+      gpg_err_set_errno (saved_err);
       return -1;
     }
 
       return -1;
     }
 
@@ -2117,28 +2559,28 @@ copy_file (const char *src_name, const char *dst_name)
     {
       int written;
 
     {
       int written;
 
-      len = fread (buffer, 1, BUF_LEN, src);
+      len = gpgrt_fread (buffer, 1, BUF_LEN, src);
       if (len == 0)
        break;
       if (len == 0)
        break;
-      written = fwrite (buffer, 1, len, dst);
+      written = gpgrt_fwrite (buffer, 1, len, dst);
       if (written != len)
        break;
     }
       if (written != len)
        break;
     }
-  while (!feof (src) && !ferror (src) && !ferror (dst));
+  while (! gpgrt_feof (src) && ! gpgrt_ferror (src) && ! gpgrt_ferror (dst));
 
 
-  if (ferror (src) || ferror (dst) || !feof (src))
+  if (gpgrt_ferror (src) || gpgrt_ferror (dst) || ! gpgrt_feof (src))
     {
       int saved_errno = errno;
     {
       int saved_errno = errno;
-      fclose (src);
-      fclose (dst);
+      gpgrt_fclose (src);
+      gpgrt_fclose (dst);
       unlink (dst_name);
       unlink (dst_name);
-      errno = saved_errno;
+      gpg_err_set_errno (saved_errno);
       return -1;
     }
 
       return -1;
     }
 
-  if (fclose (dst) && ferror (dst))
+  if (gpgrt_fclose (dst))
     gc_error (1, errno, "error closing %s", dst_name);
     gc_error (1, errno, "error closing %s", dst_name);
-  if (fclose (src) && ferror (src))
+  if (gpgrt_fclose (src))
     gc_error (1, errno, "error closing %s", src_name);
 
   return 0;
     gc_error (1, errno, "error closing %s", src_name);
 
   return 0;
@@ -2147,13 +2589,26 @@ copy_file (const char *src_name, const char *dst_name)
 
 
 /* Create and verify the new configuration file for the specified
 
 
 /* Create and verify the new configuration file for the specified
-   backend and component.  Returns 0 on success and -1 on error.  */
+ * backend and component.  Returns 0 on success and -1 on error.  This
+ * function may store pointers to malloced strings in SRC_FILENAMEP,
+ * DEST_FILENAMEP, and ORIG_FILENAMEP.  Those must be freed by the
+ * caller.  The strings refer to three versions of the configuration
+ * file:
+ *
+ * SRC_FILENAME:  The updated configuration is written to this file.
+ * DEST_FILENAME: Name of the configuration file read by the
+ *                component.
+ * ORIG_FILENAME: A backup of the previous configuration file.
+ *
+ * To apply the configuration change, rename SRC_FILENAME to
+ * DEST_FILENAME.  To revert to the previous configuration, rename
+ * ORIG_FILENAME to DEST_FILENAME.  */
 static int
 change_options_file (gc_component_t component, gc_backend_t backend,
                     char **src_filenamep, char **dest_filenamep,
                     char **orig_filenamep)
 {
 static int
 change_options_file (gc_component_t component, gc_backend_t backend,
                     char **src_filenamep, char **dest_filenamep,
                     char **orig_filenamep)
 {
-  static const char marker[] = "###+++--- GPGConf ---+++###";
+  static const char marker[] = "###+++--- " GPGCONF_DISP_NAME " ---+++###";
   /* True if we are within the marker in the config file.  */
   int in_marker = 0;
   gc_option_t *option;
   /* True if we are within the marker in the config file.  */
   int in_marker = 0;
   gc_option_t *option;
@@ -2162,8 +2617,8 @@ change_options_file (gc_component_t component, gc_backend_t backend,
   ssize_t length;
   int res;
   int fd;
   ssize_t length;
   int res;
   int fd;
-  FILE *src_file = NULL;
-  FILE *dest_file = NULL;
+  gpgrt_stream_t src_file = NULL;
+  gpgrt_stream_t dest_file = NULL;
   char *src_filename;
   char *dest_filename;
   char *orig_filename;
   char *src_filename;
   char *dest_filename;
   char *orig_filename;
@@ -2177,11 +2632,13 @@ change_options_file (gc_component_t component, gc_backend_t backend,
   assert (gc_arg_type[option->arg_type].fallback != GC_ARG_TYPE_NONE);
 
   /* FIXME.  Throughout the function, do better error reporting.  */
   assert (gc_arg_type[option->arg_type].fallback != GC_ARG_TYPE_NONE);
 
   /* FIXME.  Throughout the function, do better error reporting.  */
-  /* Note that get_config_pathname() calls percent_deescape(), so we
+  /* Note that get_config_filename() calls percent_deescape(), so we
      call this before processing the arguments.  */
      call this before processing the arguments.  */
-  dest_filename = xstrdup (get_config_pathname (component, backend));
-  src_filename = xasprintf ("%s.gpgconf.%i.new", dest_filename, getpid ());
-  orig_filename = xasprintf ("%s.gpgconf.%i.bak", dest_filename, getpid ());
+  dest_filename = xstrdup (get_config_filename (component, backend));
+  src_filename = xasprintf ("%s.%s.%i.new",
+                            dest_filename, GPGCONF_NAME, (int)getpid ());
+  orig_filename = xasprintf ("%s.%s.%i.bak",
+                             dest_filename, GPGCONF_NAME, (int)getpid ());
 
   arg = option->new_value;
   if (arg && arg[0] == '\0')
 
   arg = option->new_value;
   if (arg && arg[0] == '\0')
@@ -2211,7 +2668,12 @@ change_options_file (gc_component_t component, gc_backend_t backend,
   res = link (dest_filename, orig_filename);
 #endif
   if (res < 0 && errno != ENOENT)
   res = link (dest_filename, orig_filename);
 #endif
   if (res < 0 && errno != ENOENT)
-    return -1;
+    {
+      xfree (dest_filename);
+      xfree (src_filename);
+      xfree (orig_filename);
+      return -1;
+    }
   if (res < 0)
     {
       xfree (orig_filename);
   if (res < 0)
     {
       xfree (orig_filename);
@@ -2228,11 +2690,11 @@ change_options_file (gc_component_t component, gc_backend_t backend,
   fd = open (src_filename, O_CREAT | O_EXCL | O_WRONLY, 0644);
   if (fd < 0)
     return -1;
   fd = open (src_filename, O_CREAT | O_EXCL | O_WRONLY, 0644);
   if (fd < 0)
     return -1;
-  src_file = fdopen (fd, "w");
+  src_file = gpgrt_fdopen (fd, "w");
   res = errno;
   if (!src_file)
     {
   res = errno;
   if (!src_file)
     {
-      errno = res;
+      gpg_err_set_errno (res);
       return -1;
     }
 
       return -1;
     }
 
@@ -2242,11 +2704,11 @@ change_options_file (gc_component_t component, gc_backend_t backend,
      process.  */
   if (orig_filename)
     {
      process.  */
   if (orig_filename)
     {
-      dest_file = fopen (dest_filename, "r");
+      dest_file = gpgrt_fopen (dest_filename, "r");
       if (!dest_file)
        goto change_file_one_err;
 
       if (!dest_file)
        goto change_file_one_err;
 
-      while ((length = read_line (dest_file, &line, &line_len, NULL)) > 0)
+      while ((length = gpgrt_read_line (dest_file, &line, &line_len, NULL)) > 0)
        {
          int disable = 0;
          char *start;
        {
          int disable = 0;
          char *start;
@@ -2317,24 +2779,24 @@ change_options_file (gc_component_t component, gc_backend_t backend,
            {
              if (!in_marker)
                {
            {
              if (!in_marker)
                {
-                 fprintf (src_file,
-                          "# GPGConf disabled this option here at %s\n",
-                          asctimestamp (gnupg_get_time ()));
-                 if (ferror (src_file))
+                 gpgrt_fprintf (src_file,
+                          "# %s disabled this option here at %s\n",
+                          GPGCONF_DISP_NAME, asctimestamp (gnupg_get_time ()));
+                 if (gpgrt_ferror (src_file))
                    goto change_file_one_err;
                    goto change_file_one_err;
-                 fprintf (src_file, "# %s", line);
-                 if (ferror (src_file))
+                 gpgrt_fprintf (src_file, "# %s", line);
+                 if (gpgrt_ferror (src_file))
                    goto change_file_one_err;
                }
            }
          else
            {
                    goto change_file_one_err;
                }
            }
          else
            {
-             fprintf (src_file, "%s", line);
-             if (ferror (src_file))
+             gpgrt_fprintf (src_file, "%s", line);
+             if (gpgrt_ferror (src_file))
                goto change_file_one_err;
            }
        }
                goto change_file_one_err;
            }
        }
-      if (length < 0 || ferror (dest_file))
+      if (length < 0 || gpgrt_ferror (dest_file))
        goto change_file_one_err;
     }
 
        goto change_file_one_err;
     }
 
@@ -2345,8 +2807,8 @@ change_options_file (gc_component_t component, gc_backend_t backend,
         proceed.  Note that we first write a newline, this guards us
         against files which lack the newline at the end of the last
         line, while it doesn't hurt us in all other cases.  */
         proceed.  Note that we first write a newline, this guards us
         against files which lack the newline at the end of the last
         line, while it doesn't hurt us in all other cases.  */
-      fprintf (src_file, "\n%s\n", marker);
-      if (ferror (src_file))
+      gpgrt_fprintf (src_file, "\n%s\n", marker);
+      if (gpgrt_ferror (src_file))
        goto change_file_one_err;
     }
 
        goto change_file_one_err;
     }
 
@@ -2356,7 +2818,7 @@ change_options_file (gc_component_t component, gc_backend_t backend,
      followed by the rest of the original file.  */
   while (cur_arg)
     {
      followed by the rest of the original file.  */
   while (cur_arg)
     {
-      fprintf (src_file, "%s\n", cur_arg);
+      gpgrt_fprintf (src_file, "%s\n", cur_arg);
 
       /* Find next argument.  */
       if (arg)
 
       /* Find next argument.  */
       if (arg)
@@ -2381,51 +2843,52 @@ change_options_file (gc_component_t component, gc_backend_t backend,
        cur_arg = NULL;
     }
 
        cur_arg = NULL;
     }
 
-  fprintf (src_file, "%s %s\n", marker, asctimestamp (gnupg_get_time ()));
-  if (ferror (src_file))
+  gpgrt_fprintf (src_file, "%s %s\n", marker, asctimestamp (gnupg_get_time ()));
+  if (gpgrt_ferror (src_file))
     goto change_file_one_err;
 
   if (!in_marker)
     {
     goto change_file_one_err;
 
   if (!in_marker)
     {
-      fprintf (src_file, "# GPGConf edited this configuration file.\n");
-      if (ferror (src_file))
+      gpgrt_fprintf (src_file, "# %s edited this configuration file.\n",
+               GPGCONF_DISP_NAME);
+      if (gpgrt_ferror (src_file))
        goto change_file_one_err;
        goto change_file_one_err;
-      fprintf (src_file, "# It will disable options before this marked "
+      gpgrt_fprintf (src_file, "# It will disable options before this marked "
               "block, but it will\n");
               "block, but it will\n");
-      if (ferror (src_file))
+      if (gpgrt_ferror (src_file))
        goto change_file_one_err;
        goto change_file_one_err;
-      fprintf (src_file, "# never change anything below these lines.\n");
-      if (ferror (src_file))
+      gpgrt_fprintf (src_file, "# never change anything below these lines.\n");
+      if (gpgrt_ferror (src_file))
        goto change_file_one_err;
     }
   if (dest_file)
     {
        goto change_file_one_err;
     }
   if (dest_file)
     {
-      while ((length = read_line (dest_file, &line, &line_len, NULL)) > 0)
+      while ((length = gpgrt_read_line (dest_file, &line, &line_len, NULL)) > 0)
        {
        {
-         fprintf (src_file, "%s", line);
-         if (ferror (src_file))
+         gpgrt_fprintf (src_file, "%s", line);
+         if (gpgrt_ferror (src_file))
            goto change_file_one_err;
        }
            goto change_file_one_err;
        }
-      if (length < 0 || ferror (dest_file))
+      if (length < 0 || gpgrt_ferror (dest_file))
        goto change_file_one_err;
     }
   xfree (line);
   line = NULL;
 
        goto change_file_one_err;
     }
   xfree (line);
   line = NULL;
 
-  res = fclose (src_file);
+  res = gpgrt_fclose (src_file);
   if (res)
     {
       res = errno;
       close (fd);
       if (dest_file)
   if (res)
     {
       res = errno;
       close (fd);
       if (dest_file)
-       fclose (dest_file);
-      errno = res;
+       gpgrt_fclose (dest_file);
+      gpg_err_set_errno (res);
       return -1;
     }
   close (fd);
   if (dest_file)
     {
       return -1;
     }
   close (fd);
   if (dest_file)
     {
-      res = fclose (dest_file);
+      res = gpgrt_fclose (dest_file);
       if (res)
        return -1;
     }
       if (res)
        return -1;
     }
@@ -2436,24 +2899,38 @@ change_options_file (gc_component_t component, gc_backend_t backend,
   res = errno;
   if (src_file)
     {
   res = errno;
   if (src_file)
     {
-      fclose (src_file);
+      gpgrt_fclose (src_file);
       close (fd);
     }
   if (dest_file)
       close (fd);
     }
   if (dest_file)
-    fclose (dest_file);
-  errno = res;
+    gpgrt_fclose (dest_file);
+  gpg_err_set_errno (res);
   return -1;
 }
 
 
 /* Create and verify the new configuration file for the specified
   return -1;
 }
 
 
 /* Create and verify the new configuration file for the specified
-   backend and component.  Returns 0 on success and -1 on error.  */
+ * backend and component.  Returns 0 on success and -1 on error.  If
+ * VERBATIM is set the profile mode is used.  This function may store
+ * pointers to malloced strings in SRC_FILENAMEP, DEST_FILENAMEP, and
+ * ORIG_FILENAMEP.  Those must be freed by the caller.  The strings
+ * refer to three versions of the configuration file:
+ *
+ * SRC_FILENAME:  The updated configuration is written to this file.
+ * DEST_FILENAME: Name of the configuration file read by the
+ *                component.
+ * ORIG_FILENAME: A backup of the previous configuration file.
+ *
+ * To apply the configuration change, rename SRC_FILENAME to
+ * DEST_FILENAME.  To revert to the previous configuration, rename
+ * ORIG_FILENAME to DEST_FILENAME.  */
 static int
 change_options_program (gc_component_t component, gc_backend_t backend,
                        char **src_filenamep, char **dest_filenamep,
 static int
 change_options_program (gc_component_t component, gc_backend_t backend,
                        char **src_filenamep, char **dest_filenamep,
-                       char **orig_filenamep)
+                       char **orig_filenamep,
+                        int verbatim)
 {
 {
-  static const char marker[] = "###+++--- GPGConf ---+++###";
+  static const char marker[] = "###+++--- " GPGCONF_DISP_NAME " ---+++###";
   /* True if we are within the marker in the config file.  */
   int in_marker = 0;
   gc_option_t *option;
   /* True if we are within the marker in the config file.  */
   int in_marker = 0;
   gc_option_t *option;
@@ -2462,8 +2939,8 @@ change_options_program (gc_component_t component, gc_backend_t backend,
   ssize_t length;
   int res;
   int fd;
   ssize_t length;
   int res;
   int fd;
-  FILE *src_file = NULL;
-  FILE *dest_file = NULL;
+  gpgrt_stream_t src_file = NULL;
+  gpgrt_stream_t dest_file = NULL;
   char *src_filename;
   char *dest_filename;
   char *orig_filename;
   char *src_filename;
   char *dest_filename;
   char *orig_filename;
@@ -2471,9 +2948,11 @@ change_options_program (gc_component_t component, gc_backend_t backend,
   int utf8strings_seen = 0;
 
   /* FIXME.  Throughout the function, do better error reporting.  */
   int utf8strings_seen = 0;
 
   /* FIXME.  Throughout the function, do better error reporting.  */
-  dest_filename = xstrdup (get_config_pathname (component, backend));
-  src_filename = xasprintf ("%s.gpgconf.%i.new", dest_filename, getpid ());
-  orig_filename = xasprintf ("%s.gpgconf.%i.bak", dest_filename, getpid ());
+  dest_filename = xstrdup (get_config_filename (component, backend));
+  src_filename = xasprintf ("%s.%s.%i.new",
+                            dest_filename, GPGCONF_NAME, (int)getpid ());
+  orig_filename = xasprintf ("%s.%s.%i.bak",
+                             dest_filename, GPGCONF_NAME, (int)getpid ());
 
 #ifdef HAVE_W32_SYSTEM
   res = copy_file (dest_filename, orig_filename);
 
 #ifdef HAVE_W32_SYSTEM
   res = copy_file (dest_filename, orig_filename);
@@ -2481,7 +2960,12 @@ change_options_program (gc_component_t component, gc_backend_t backend,
   res = link (dest_filename, orig_filename);
 #endif
   if (res < 0 && errno != ENOENT)
   res = link (dest_filename, orig_filename);
 #endif
   if (res < 0 && errno != ENOENT)
-    return -1;
+    {
+      xfree (dest_filename);
+      xfree (src_filename);
+      xfree (orig_filename);
+      return -1;
+    }
   if (res < 0)
     {
       xfree (orig_filename);
   if (res < 0)
     {
       xfree (orig_filename);
@@ -2498,11 +2982,11 @@ change_options_program (gc_component_t component, gc_backend_t backend,
   fd = open (src_filename, O_CREAT | O_EXCL | O_WRONLY, 0644);
   if (fd < 0)
     return -1;
   fd = open (src_filename, O_CREAT | O_EXCL | O_WRONLY, 0644);
   if (fd < 0)
     return -1;
-  src_file = fdopen (fd, "w");
+  src_file = gpgrt_fdopen (fd, "w");
   res = errno;
   if (!src_file)
     {
   res = errno;
   if (!src_file)
     {
-      errno = res;
+      gpg_err_set_errno (res);
       return -1;
     }
 
       return -1;
     }
 
@@ -2512,11 +2996,11 @@ change_options_program (gc_component_t component, gc_backend_t backend,
      process.  */
   if (orig_filename)
     {
      process.  */
   if (orig_filename)
     {
-      dest_file = fopen (dest_filename, "r");
+      dest_file = gpgrt_fopen (dest_filename, "r");
       if (!dest_file)
        goto change_one_err;
 
       if (!dest_file)
        goto change_one_err;
 
-      while ((length = read_line (dest_file, &line, &line_len, NULL)) > 0)
+      while ((length = gpgrt_read_line (dest_file, &line, &line_len, NULL)) > 0)
        {
          int disable = 0;
          char *start;
        {
          int disable = 0;
          char *start;
@@ -2563,24 +3047,24 @@ change_options_program (gc_component_t component, gc_backend_t backend,
            {
              if (!in_marker)
                {
            {
              if (!in_marker)
                {
-                 fprintf (src_file,
-                          "# GPGConf disabled this option here at %s\n",
-                          asctimestamp (gnupg_get_time ()));
-                 if (ferror (src_file))
+                 gpgrt_fprintf (src_file,
+                          "# %s disabled this option here at %s\n",
+                          GPGCONF_DISP_NAME, asctimestamp (gnupg_get_time ()));
+                 if (gpgrt_ferror (src_file))
                    goto change_one_err;
                    goto change_one_err;
-                 fprintf (src_file, "# %s", line);
-                 if (ferror (src_file))
+                 gpgrt_fprintf (src_file, "# %s", line);
+                 if (gpgrt_ferror (src_file))
                    goto change_one_err;
                }
            }
          else
            {
                    goto change_one_err;
                }
            }
          else
            {
-             fprintf (src_file, "%s", line);
-             if (ferror (src_file))
+             gpgrt_fprintf (src_file, "%s", line);
+             if (gpgrt_ferror (src_file))
                goto change_one_err;
            }
        }
                goto change_one_err;
            }
        }
-      if (length < 0 || ferror (dest_file))
+      if (length < 0 || gpgrt_ferror (dest_file))
        goto change_one_err;
     }
 
        goto change_one_err;
     }
 
@@ -2591,8 +3075,8 @@ change_options_program (gc_component_t component, gc_backend_t backend,
         proceed.  Note that we first write a newline, this guards us
         against files which lack the newline at the end of the last
         line, while it doesn't hurt us in all other cases.  */
         proceed.  Note that we first write a newline, this guards us
         against files which lack the newline at the end of the last
         line, while it doesn't hurt us in all other cases.  */
-      fprintf (src_file, "\n%s\n", marker);
-      if (ferror (src_file))
+      gpgrt_fprintf (src_file, "\n%s\n", marker);
+      if (gpgrt_ferror (src_file))
        goto change_one_err;
     }
   /* At this point, we have copied everything up to the end marker
        goto change_one_err;
     }
   /* At this point, we have copied everything up to the end marker
@@ -2603,7 +3087,7 @@ change_options_program (gc_component_t component, gc_backend_t backend,
 
   /* We have to turn on UTF8 strings for GnuPG.  */
   if (backend == GC_BACKEND_GPG && ! utf8strings_seen)
 
   /* We have to turn on UTF8 strings for GnuPG.  */
   if (backend == GC_BACKEND_GPG && ! utf8strings_seen)
-    fprintf (src_file, "utf8-strings\n");
+    gpgrt_fprintf (src_file, "utf8-strings\n");
 
   option = gc_component[component].options;
   while (option->name)
 
   option = gc_component[component].options;
   while (option->name)
@@ -2618,16 +3102,16 @@ change_options_program (gc_component_t component, gc_backend_t backend,
            {
              if (*arg == '\0' || *arg == ',')
                {
            {
              if (*arg == '\0' || *arg == ',')
                {
-                 fprintf (src_file, "%s\n", option->name);
-                 if (ferror (src_file))
+                 gpgrt_fprintf (src_file, "%s\n", option->name);
+                 if (gpgrt_ferror (src_file))
                    goto change_one_err;
                }
              else if (gc_arg_type[option->arg_type].fallback
                       == GC_ARG_TYPE_NONE)
                {
                  assert (*arg == '1');
                    goto change_one_err;
                }
              else if (gc_arg_type[option->arg_type].fallback
                       == GC_ARG_TYPE_NONE)
                {
                  assert (*arg == '1');
-                 fprintf (src_file, "%s\n", option->name);
-                 if (ferror (src_file))
+                 gpgrt_fprintf (src_file, "%s\n", option->name);
+                 if (gpgrt_ferror (src_file))
                    goto change_one_err;
 
                  arg++;
                    goto change_one_err;
 
                  arg++;
@@ -2636,17 +3120,22 @@ change_options_program (gc_component_t component, gc_backend_t backend,
                       == GC_ARG_TYPE_STRING)
                {
                  char *end;
                       == GC_ARG_TYPE_STRING)
                {
                  char *end;
-                 
-                 assert (*arg == '"');
-                 arg++;
-                 
-                 end = strchr (arg, ',');
-                 if (end)
-                   *end = '\0';
 
 
-                 fprintf (src_file, "%s %s\n", option->name,
-                          percent_deescape (arg));
-                 if (ferror (src_file))
+                  if (!verbatim)
+                    {
+                      log_assert (*arg == '"');
+                      arg++;
+
+                      end = strchr (arg, ',');
+                      if (end)
+                        *end = '\0';
+                    }
+                  else
+                    end = NULL;
+
+                 gpgrt_fprintf (src_file, "%s %s\n", option->name,
+                          verbatim? arg : percent_deescape (arg));
+                 if (gpgrt_ferror (src_file))
                    goto change_one_err;
 
                  if (end)
                    goto change_one_err;
 
                  if (end)
@@ -2661,8 +3150,8 @@ change_options_program (gc_component_t component, gc_backend_t backend,
                  if (end)
                    *end = '\0';
 
                  if (end)
                    *end = '\0';
 
-                 fprintf (src_file, "%s %s\n", option->name, arg);
-                 if (ferror (src_file))
+                 gpgrt_fprintf (src_file, "%s %s\n", option->name, arg);
+                 if (gpgrt_ferror (src_file))
                    goto change_one_err;
 
                  if (end)
                    goto change_one_err;
 
                  if (end)
@@ -2679,51 +3168,52 @@ change_options_program (gc_component_t component, gc_backend_t backend,
       option++;
     }
 
       option++;
     }
 
-  fprintf (src_file, "%s %s\n", marker, asctimestamp (gnupg_get_time ()));
-  if (ferror (src_file))
+  gpgrt_fprintf (src_file, "%s %s\n", marker, asctimestamp (gnupg_get_time ()));
+  if (gpgrt_ferror (src_file))
     goto change_one_err;
 
   if (!in_marker)
     {
     goto change_one_err;
 
   if (!in_marker)
     {
-      fprintf (src_file, "# GPGConf edited this configuration file.\n");
-      if (ferror (src_file))
+      gpgrt_fprintf (src_file, "# %s edited this configuration file.\n",
+               GPGCONF_DISP_NAME);
+      if (gpgrt_ferror (src_file))
        goto change_one_err;
        goto change_one_err;
-      fprintf (src_file, "# It will disable options before this marked "
+      gpgrt_fprintf (src_file, "# It will disable options before this marked "
               "block, but it will\n");
               "block, but it will\n");
-      if (ferror (src_file))
+      if (gpgrt_ferror (src_file))
        goto change_one_err;
        goto change_one_err;
-      fprintf (src_file, "# never change anything below these lines.\n");
-      if (ferror (src_file))
+      gpgrt_fprintf (src_file, "# never change anything below these lines.\n");
+      if (gpgrt_ferror (src_file))
        goto change_one_err;
     }
   if (dest_file)
     {
        goto change_one_err;
     }
   if (dest_file)
     {
-      while ((length = read_line (dest_file, &line, &line_len, NULL)) > 0)
+      while ((length = gpgrt_read_line (dest_file, &line, &line_len, NULL)) > 0)
        {
        {
-         fprintf (src_file, "%s", line);
-         if (ferror (src_file))
+         gpgrt_fprintf (src_file, "%s", line);
+         if (gpgrt_ferror (src_file))
            goto change_one_err;
        }
            goto change_one_err;
        }
-      if (length < 0 || ferror (dest_file))
+      if (length < 0 || gpgrt_ferror (dest_file))
        goto change_one_err;
     }
   xfree (line);
   line = NULL;
 
        goto change_one_err;
     }
   xfree (line);
   line = NULL;
 
-  res = fclose (src_file);
+  res = gpgrt_fclose (src_file);
   if (res)
     {
       res = errno;
       close (fd);
       if (dest_file)
   if (res)
     {
       res = errno;
       close (fd);
       if (dest_file)
-       fclose (dest_file);
-      errno = res;
+       gpgrt_fclose (dest_file);
+      gpg_err_set_errno (res);
       return -1;
     }
   close (fd);
   if (dest_file)
     {
       return -1;
     }
   close (fd);
   if (dest_file)
     {
-      res = fclose (dest_file);
+      res = gpgrt_fclose (dest_file);
       if (res)
        return -1;
     }
       if (res)
        return -1;
     }
@@ -2734,25 +3224,26 @@ change_options_program (gc_component_t component, gc_backend_t backend,
   res = errno;
   if (src_file)
     {
   res = errno;
   if (src_file)
     {
-      fclose (src_file);
+      gpgrt_fclose (src_file);
       close (fd);
     }
   if (dest_file)
       close (fd);
     }
   if (dest_file)
-    fclose (dest_file);
-  errno = res;
+    gpgrt_fclose (dest_file);
+  gpg_err_set_errno (res);
   return -1;
 }
 
 
 /* Common code for gc_component_change_options and
   return -1;
 }
 
 
 /* Common code for gc_component_change_options and
-   gc_process_gpgconf_conf.  */
+ * gc_process_gpgconf_conf.  If VERBATIM is set the profile parsing
+ * mode is used.  */
 static void
 change_one_value (gc_option_t *option, int *runtime,
 static void
 change_one_value (gc_option_t *option, int *runtime,
-                  unsigned long flags, char *new_value)
+                  unsigned long flags, char *new_value, int verbatim)
 {
   unsigned long new_value_nr = 0;
 
 {
   unsigned long new_value_nr = 0;
 
-  option_check_validity (option, flags, new_value, &new_value_nr);
+  option_check_validity (option, flags, new_value, &new_value_nr, verbatim);
 
   if (option->flags & GC_OPT_FLAG_RUNTIME)
     runtime[option->backend] = 1;
 
   if (option->flags & GC_OPT_FLAG_RUNTIME)
     runtime[option->backend] = 1;
@@ -2786,47 +3277,52 @@ change_one_value (gc_option_t *option, int *runtime,
 
 /* Read the modifications from IN and apply them.  If IN is NULL the
    modifications are expected to already have been set to the global
 
 /* Read the modifications from IN and apply them.  If IN is NULL the
    modifications are expected to already have been set to the global
-   table. */
+   table.  If VERBATIM is set the profile mode is used.  */
 void
 void
-gc_component_change_options (int component, FILE *in)
+gc_component_change_options (int component, estream_t in, estream_t out,
+                             int verbatim)
 {
   int err = 0;
 {
   int err = 0;
+  int block = 0;
   int runtime[GC_BACKEND_NR];
   int runtime[GC_BACKEND_NR];
-  char *src_pathname[GC_BACKEND_NR];
-  char *dest_pathname[GC_BACKEND_NR];
-  char *orig_pathname[GC_BACKEND_NR];
+  char *src_filename[GC_BACKEND_NR];
+  char *dest_filename[GC_BACKEND_NR];
+  char *orig_filename[GC_BACKEND_NR];
   gc_backend_t backend;
   gc_option_t *option;
   char *line = NULL;
   size_t line_len = 0;
   ssize_t length;
 
   gc_backend_t backend;
   gc_option_t *option;
   char *line = NULL;
   size_t line_len = 0;
   ssize_t length;
 
+  if (component == GC_COMPONENT_PINENTRY)
+    return; /* Dummy component for now.  */
+
   for (backend = 0; backend < GC_BACKEND_NR; backend++)
     {
       runtime[backend] = 0;
   for (backend = 0; backend < GC_BACKEND_NR; backend++)
     {
       runtime[backend] = 0;
-      src_pathname[backend] = NULL;
-      dest_pathname[backend] = NULL;
-      orig_pathname[backend] = NULL;
+      src_filename[backend] = NULL;
+      dest_filename[backend] = NULL;
+      orig_filename[backend] = NULL;
     }
 
   if (in)
     {
       /* Read options from the file IN.  */
     }
 
   if (in)
     {
       /* Read options from the file IN.  */
-      while ((length = read_line (in, &line, &line_len, NULL)) > 0)
+      while ((length = es_read_line (in, &line, &line_len, NULL)) > 0)
         {
           char *linep;
           unsigned long flags = 0;
           char *new_value = "";
         {
           char *linep;
           unsigned long flags = 0;
           char *new_value = "";
-          
+
           /* Strip newline and carriage return, if present.  */
           while (length > 0
                  && (line[length - 1] == '\n' || line[length - 1] == '\r'))
             line[--length] = '\0';
           /* Strip newline and carriage return, if present.  */
           while (length > 0
                  && (line[length - 1] == '\n' || line[length - 1] == '\r'))
             line[--length] = '\0';
-          
+
           linep = strchr (line, ':');
           if (linep)
             *(linep++) = '\0';
           linep = strchr (line, ':');
           if (linep)
             *(linep++) = '\0';
-          
+
           /* Extract additional flags.  Default to none.  */
           if (linep)
             {
           /* Extract additional flags.  Default to none.  */
           if (linep)
             {
@@ -2836,20 +3332,20 @@ gc_component_change_options (int component, FILE *in)
               end = strchr (linep, ':');
               if (end)
                 *(end++) = '\0';
               end = strchr (linep, ':');
               if (end)
                 *(end++) = '\0';
-              
-              errno = 0;
+
+              gpg_err_set_errno (0);
               flags = strtoul (linep, &tail, 0);
               if (errno)
                 gc_error (1, errno, "malformed flags in option %s", line);
               if (!(*tail == '\0' || *tail == ':' || *tail == ' '))
                 gc_error (1, 0, "garbage after flags in option %s", line);
               flags = strtoul (linep, &tail, 0);
               if (errno)
                 gc_error (1, errno, "malformed flags in option %s", line);
               if (!(*tail == '\0' || *tail == ':' || *tail == ' '))
                 gc_error (1, 0, "garbage after flags in option %s", line);
-              
+
               linep = end;
             }
 
           /* Don't allow setting of the no change flag.  */
           flags &= ~GC_OPT_FLAG_NO_CHANGE;
               linep = end;
             }
 
           /* Don't allow setting of the no change flag.  */
           flags &= ~GC_OPT_FLAG_NO_CHANGE;
-          
+
           /* Extract default value, if present.  Default to empty if not.  */
           if (linep)
             {
           /* Extract default value, if present.  Default to empty if not.  */
           if (linep)
             {
@@ -2860,20 +3356,22 @@ gc_component_change_options (int component, FILE *in)
               new_value = linep;
               linep = end;
             }
               new_value = linep;
               linep = end;
             }
-          
+
           option = find_option (component, line, GC_BACKEND_ANY);
           if (!option)
             gc_error (1, 0, "unknown option %s", line);
           option = find_option (component, line, GC_BACKEND_ANY);
           if (!option)
             gc_error (1, 0, "unknown option %s", line);
-          
+
           if ((option->flags & GC_OPT_FLAG_NO_CHANGE))
             {
               gc_error (0, 0, "ignoring new value for option %s",
                         option->name);
               continue;
             }
           if ((option->flags & GC_OPT_FLAG_NO_CHANGE))
             {
               gc_error (0, 0, "ignoring new value for option %s",
                         option->name);
               continue;
             }
-          
-          change_one_value (option, runtime, flags, new_value);
+
+          change_one_value (option, runtime, flags, new_value, 0);
         }
         }
+      if (length < 0 || gpgrt_ferror (in))
+       gc_error (1, errno, "error reading stream 'in'");
     }
 
   /* Now that we have collected and locally verified the changes,
     }
 
   /* Now that we have collected and locally verified the changes,
@@ -2884,7 +3382,7 @@ gc_component_change_options (int component, FILE *in)
     {
       /* Go on if we have already seen this backend, or if there is
         nothing to do.  */
     {
       /* Go on if we have already seen this backend, or if there is
         nothing to do.  */
-      if (src_pathname[option->backend]
+      if (src_filename[option->backend]
          || !(option->new_flags || option->new_value))
        {
          option++;
          || !(option->new_flags || option->new_value))
        {
          option++;
@@ -2892,79 +3390,98 @@ gc_component_change_options (int component, FILE *in)
        }
 
       if (gc_backend[option->backend].program)
        }
 
       if (gc_backend[option->backend].program)
-       err = change_options_program (component, option->backend,
-                                     &src_pathname[option->backend],
-                                     &dest_pathname[option->backend],
-                                     &orig_pathname[option->backend]);
+       {
+         err = change_options_program (component, option->backend,
+                                       &src_filename[option->backend],
+                                       &dest_filename[option->backend],
+                                       &orig_filename[option->backend],
+                                        verbatim);
+         if (! err)
+           {
+             /* External verification.  */
+             err = gc_component_check_options (component, out,
+                                               src_filename[option->backend]);
+             if (err)
+               {
+                 gc_error (0, 0,
+                           _("External verification of component %s failed"),
+                           gc_component[component].name);
+                 gpg_err_set_errno (EINVAL);
+               }
+           }
+
+       }
       else
        err = change_options_file (component, option->backend,
       else
        err = change_options_file (component, option->backend,
-                                  &src_pathname[option->backend],
-                                  &dest_pathname[option->backend],
-                                  &orig_pathname[option->backend]);
-       
+                                  &src_filename[option->backend],
+                                  &dest_filename[option->backend],
+                                  &orig_filename[option->backend]);
+
       if (err)
        break;
       if (err)
        break;
-         
+
       option++;
     }
 
       option++;
     }
 
-  if (!err)
+  /* We are trying to atomically commit all changes.  Unfortunately,
+     we cannot rely on gnupg_rename_file to manage the signals for us,
+     doing so would require us to pass NULL as BLOCK to any subsequent
+     call to it.  Instead, we just manage the signal handling
+     manually.  */
+  block = 1;
+  gnupg_block_all_signals ();
+
+  if (! err && ! opt.dry_run)
     {
       int i;
 
       for (i = 0; i < GC_BACKEND_NR; i++)
        {
     {
       int i;
 
       for (i = 0; i < GC_BACKEND_NR; i++)
        {
-         if (src_pathname[i])
+         if (src_filename[i])
            {
              /* FIXME: Make a verification here.  */
 
            {
              /* FIXME: Make a verification here.  */
 
-             assert (dest_pathname[i]);
+             assert (dest_filename[i]);
 
 
-             if (orig_pathname[i])
-               {
-#ifdef HAVE_W32_SYSTEM
-                 /* There is no atomic update on W32.  */
-                 err = unlink (dest_pathname[i]);
-#endif /* HAVE_W32_SYSTEM */
-                 if (!err)
-                   err = rename (src_pathname[i], dest_pathname[i]);
-               }
+             if (orig_filename[i])
+               err = gnupg_rename_file (src_filename[i], dest_filename[i], NULL);
              else
                {
 #ifdef HAVE_W32_SYSTEM
                  /* We skip the unlink if we expect the file not to
                     be there.  */
              else
                {
 #ifdef HAVE_W32_SYSTEM
                  /* We skip the unlink if we expect the file not to
                     be there.  */
-                  err = rename (src_pathname[i], dest_pathname[i]);
+                  err = gnupg_rename_file (src_filename[i], dest_filename[i], NULL);
 #else /* HAVE_W32_SYSTEM */
                  /* This is a bit safer than rename() because we
 #else /* HAVE_W32_SYSTEM */
                  /* This is a bit safer than rename() because we
-                    expect DEST_PATHNAME not to be there.  If it
+                    expect DEST_FILENAME not to be there.  If it
                     happens to be there, this will fail.  */
                     happens to be there, this will fail.  */
-                 err = link (src_pathname[i], dest_pathname[i]);
+                 err = link (src_filename[i], dest_filename[i]);
                  if (!err)
                  if (!err)
-                   err = unlink (src_pathname[i]);
+                   err = unlink (src_filename[i]);
 #endif /* !HAVE_W32_SYSTEM */
                }
              if (err)
                break;
 #endif /* !HAVE_W32_SYSTEM */
                }
              if (err)
                break;
-             src_pathname[i] = NULL;
+             xfree (src_filename[i]);
+             src_filename[i] = NULL;
            }
        }
     }
 
            }
        }
     }
 
-  if (err)
+  if (err || opt.dry_run)
     {
       int i;
       int saved_errno = errno;
 
     {
       int i;
       int saved_errno = errno;
 
-      /* An error occured.  */
+      /* An error occurred or a dry-run is requested.  */
       for (i = 0; i < GC_BACKEND_NR; i++)
        {
       for (i = 0; i < GC_BACKEND_NR; i++)
        {
-         if (src_pathname[i])
+         if (src_filename[i])
            {
              /* The change was not yet committed.  */
            {
              /* The change was not yet committed.  */
-             unlink (src_pathname[i]);
-             if (orig_pathname[i])
-               unlink (orig_pathname[i]);
+             unlink (src_filename[i]);
+             if (orig_filename[i])
+               unlink (orig_filename[i]);
            }
          else
            {
            }
          else
            {
@@ -2972,47 +3489,51 @@ gc_component_change_options (int component, FILE *in)
                 tad dangerous, as we don't know if we don't overwrite
                 a version of the file that is even newer than the one
                 we just installed.  */
                 tad dangerous, as we don't know if we don't overwrite
                 a version of the file that is even newer than the one
                 we just installed.  */
-             if (orig_pathname[i])
-               {
-#ifdef HAVE_W32_SYSTEM
-                 /* There is no atomic update on W32.  */
-                 unlink (dest_pathname[i]);
-#endif /* HAVE_W32_SYSTEM */
-                 rename (orig_pathname[i], dest_pathname[i]);
-               }
+             if (orig_filename[i])
+               gnupg_rename_file (orig_filename[i], dest_filename[i], NULL);
              else
              else
-               unlink (dest_pathname[i]);
+               unlink (dest_filename[i]);
            }
        }
            }
        }
-      gc_error (1, saved_errno, "could not commit changes");
+      if (err)
+       gc_error (1, saved_errno, "could not commit changes");
+
+      /* Fall-through for dry run.  */
+      goto leave;
     }
 
   /* If it all worked, notify the daemons of the changes.  */
   if (opt.runtime)
     }
 
   /* If it all worked, notify the daemons of the changes.  */
   if (opt.runtime)
-    for (backend = 0; backend < GC_BACKEND_NR; backend++)  
+    for (backend = 0; backend < GC_BACKEND_NR; backend++)
       {
        if (runtime[backend] && gc_backend[backend].runtime_change)
       {
        if (runtime[backend] && gc_backend[backend].runtime_change)
-         (*gc_backend[backend].runtime_change) ();
+         (*gc_backend[backend].runtime_change) (0);
       }
 
   /* Move the per-process backup file into its place.  */
       }
 
   /* Move the per-process backup file into its place.  */
-  for (backend = 0; backend < GC_BACKEND_NR; backend++)  
-    if (orig_pathname[backend])
+  for (backend = 0; backend < GC_BACKEND_NR; backend++)
+    if (orig_filename[backend])
       {
       {
-       char *backup_pathname;
+       char *backup_filename;
 
 
-       assert (dest_pathname[backend]);
+       assert (dest_filename[backend]);
 
 
-       backup_pathname = xasprintf ("%s.gpgconf.bak", dest_pathname[backend]);
-
-#ifdef HAVE_W32_SYSTEM
-       /* There is no atomic update on W32.  */
-       unlink (backup_pathname);
-#endif /* HAVE_W32_SYSTEM */
-       rename (orig_pathname[backend], backup_pathname);
+       backup_filename = xasprintf ("%s.%s.bak",
+                                     dest_filename[backend], GPGCONF_NAME);
+       gnupg_rename_file (orig_filename[backend], backup_filename, NULL);
+       xfree (backup_filename);
       }
 
       }
 
+ leave:
+  if (block)
+    gnupg_unblock_all_signals ();
   xfree (line);
   xfree (line);
+  for (backend = 0; backend < GC_BACKEND_NR; backend++)
+    {
+      xfree (src_filename[backend]);
+      xfree (dest_filename[backend]);
+      xfree (orig_filename[backend]);
+    }
 }
 
 
 }
 
 
@@ -3032,9 +3553,10 @@ key_matches_user_or_group (char *user)
     *group++ = 0;
 
 #ifdef HAVE_W32_SYSTEM
     *group++ = 0;
 
 #ifdef HAVE_W32_SYSTEM
-  /* Under Windows we don't support groups. */   
+  /* Under Windows we don't support groups. */
   if (group && *group)
     gc_error (0, 0, _("Note that group specifications are ignored\n"));
   if (group && *group)
     gc_error (0, 0, _("Note that group specifications are ignored\n"));
+#ifndef HAVE_W32CE_SYSTEM
   if (*user)
     {
       static char *my_name;
   if (*user)
     {
       static char *my_name;
@@ -3054,6 +3576,7 @@ key_matches_user_or_group (char *user)
       if (!strcmp (user, my_name))
         return 1; /* Found.  */
     }
       if (!strcmp (user, my_name))
         return 1; /* Found.  */
     }
+#endif /*HAVE_W32CE_SYSTEM*/
 #else /*!HAVE_W32_SYSTEM*/
   /* First check whether the user matches.  */
   if (*user)
 #else /*!HAVE_W32_SYSTEM*/
   /* First check whether the user matches.  */
   if (*user)
@@ -3132,53 +3655,51 @@ key_matches_user_or_group (char *user)
    returned on error. */
 int
 gc_process_gpgconf_conf (const char *fname_arg, int update, int defaults,
    returned on error. */
 int
 gc_process_gpgconf_conf (const char *fname_arg, int update, int defaults,
-                         FILE *listfp)
+                         estream_t listfp)
 {
   int result = 0;
   char *line = NULL;
   size_t line_len = 0;
   ssize_t length;
 {
   int result = 0;
   char *line = NULL;
   size_t line_len = 0;
   ssize_t length;
-  FILE *config;
+  gpgrt_stream_t config;
   int lineno = 0;
   int in_rule = 0;
   int got_match = 0;
   int runtime[GC_BACKEND_NR];
   int lineno = 0;
   int in_rule = 0;
   int got_match = 0;
   int runtime[GC_BACKEND_NR];
-  int used_components[GC_COMPONENT_NR];
   int backend_id, component_id;
   char *fname;
 
   if (fname_arg)
     fname = xstrdup (fname_arg);
   else
   int backend_id, component_id;
   char *fname;
 
   if (fname_arg)
     fname = xstrdup (fname_arg);
   else
-    fname = make_filename (gnupg_sysconfdir (), "gpgconf.conf", NULL);
+    fname = make_filename (gnupg_sysconfdir (), GPGCONF_NAME EXTSEP_S "conf",
+                           NULL);
 
   for (backend_id = 0; backend_id < GC_BACKEND_NR; backend_id++)
     runtime[backend_id] = 0;
 
   for (backend_id = 0; backend_id < GC_BACKEND_NR; backend_id++)
     runtime[backend_id] = 0;
-  for (component_id = 0; component_id < GC_COMPONENT_NR; component_id++)
-    used_components[component_id] = 0;
 
 
-  config = fopen (fname, "r");
+  config = gpgrt_fopen (fname, "r");
   if (!config)
     {
       /* Do not print an error if the file is not available, except
          when running in syntax check mode.  */
       if (errno != ENOENT || !update)
         {
   if (!config)
     {
       /* Do not print an error if the file is not available, except
          when running in syntax check mode.  */
       if (errno != ENOENT || !update)
         {
-          gc_error (0, errno, "can not open global config file `%s'", fname);
+          gc_error (0, errno, "can not open global config file '%s'", fname);
           result = -1;
         }
       xfree (fname);
       return result;
     }
 
           result = -1;
         }
       xfree (fname);
       return result;
     }
 
-  while ((length = read_line (config, &line, &line_len, NULL)) > 0)
+  while ((length = gpgrt_read_line (config, &line, &line_len, NULL)) > 0)
     {
       char *key, *component, *option, *flags, *value;
       char *empty;
       gc_option_t *option_info = NULL;
       char *p;
       int is_continuation;
     {
       char *key, *component, *option, *flags, *value;
       char *empty;
       gc_option_t *option_info = NULL;
       char *p;
       int is_continuation;
-      
+
       lineno++;
       key = line;
       while (*key == ' ' || *key == '\t')
       lineno++;
       key = line;
       while (*key == ' ' || *key == '\t')
@@ -3198,7 +3719,7 @@ gc_process_gpgconf_conf (const char *fname_arg, int update, int defaults,
             ;
           if (!*p)
             {
             ;
           if (!*p)
             {
-              gc_error (0, 0, "missing rule at `%s', line %d", fname, lineno);
+              gc_error (0, 0, "missing rule at '%s', line %d", fname, lineno);
               result = -1;
               continue;
             }
               result = -1;
               continue;
             }
@@ -3207,7 +3728,7 @@ gc_process_gpgconf_conf (const char *fname_arg, int update, int defaults,
         }
       else if (!in_rule)
         {
         }
       else if (!in_rule)
         {
-          gc_error (0, 0, "continuation but no rule at `%s', line %d",
+          gc_error (0, 0, "continuation but no rule at '%s', line %d",
                     fname, lineno);
           result = -1;
           continue;
                     fname, lineno);
           result = -1;
           continue;
@@ -3227,7 +3748,7 @@ gc_process_gpgconf_conf (const char *fname_arg, int update, int defaults,
         ;
       if (p == component)
         {
         ;
       if (p == component)
         {
-          gc_error (0, 0, "missing component at `%s', line %d",
+          gc_error (0, 0, "missing component at '%s', line %d",
                     fname, lineno);
           result = -1;
           continue;
                     fname, lineno);
           result = -1;
           continue;
@@ -3238,7 +3759,7 @@ gc_process_gpgconf_conf (const char *fname_arg, int update, int defaults,
       component_id = gc_component_find (component);
       if (component_id < 0)
         {
       component_id = gc_component_find (component);
       if (component_id < 0)
         {
-          gc_error (0, 0, "unknown component at `%s', line %d",
+          gc_error (0, 0, "unknown component at '%s', line %d",
                     fname, lineno);
           result = -1;
         }
                     fname, lineno);
           result = -1;
         }
@@ -3250,7 +3771,7 @@ gc_process_gpgconf_conf (const char *fname_arg, int update, int defaults,
         ;
       if (p == option)
         {
         ;
       if (p == option)
         {
-          gc_error (0, 0, "missing option at `%s', line %d",
+          gc_error (0, 0, "missing option at '%s', line %d",
                     fname, lineno);
           result = -1;
           continue;
                     fname, lineno);
           result = -1;
           continue;
@@ -3262,7 +3783,7 @@ gc_process_gpgconf_conf (const char *fname_arg, int update, int defaults,
           option_info = find_option (component_id, option, GC_BACKEND_ANY);
           if (!option_info)
             {
           option_info = find_option (component_id, option, GC_BACKEND_ANY);
           if (!option_info)
             {
-              gc_error (0, 0, "unknown option at `%s', line %d",
+              gc_error (0, 0, "unknown option at '%s', line %d",
                         fname, lineno);
               result = -1;
             }
                         fname, lineno);
               result = -1;
             }
@@ -3278,7 +3799,7 @@ gc_process_gpgconf_conf (const char *fname_arg, int update, int defaults,
           p = strchr (flags, ']');
           if (!p)
             {
           p = strchr (flags, ']');
           if (!p)
             {
-              gc_error (0, 0, "syntax error in rule at `%s', line %d",
+              gc_error (0, 0, "syntax error in rule at '%s', line %d",
                         fname, lineno);
               result = -1;
               continue;
                         fname, lineno);
               result = -1;
               continue;
@@ -3315,7 +3836,7 @@ gc_process_gpgconf_conf (const char *fname_arg, int update, int defaults,
           if (*value)
             {
               gc_error (0, 0, "flag \"default\" may not be combined "
           if (*value)
             {
               gc_error (0, 0, "flag \"default\" may not be combined "
-                        "with a value at `%s', line %d",
+                        "with a value at '%s', line %d",
                         fname, lineno);
               result = -1;
             }
                         fname, lineno);
               result = -1;
             }
@@ -3326,7 +3847,7 @@ gc_process_gpgconf_conf (const char *fname_arg, int update, int defaults,
         ;
       else
         {
         ;
       else
         {
-          gc_error (0, 0, "unknown flag at `%s', line %d",
+          gc_error (0, 0, "unknown flag at '%s', line %d",
                     fname, lineno);
           result = -1;
         }
                     fname, lineno);
           result = -1;
         }
@@ -3343,26 +3864,26 @@ gc_process_gpgconf_conf (const char *fname_arg, int update, int defaults,
                   *group++ = 0;
                   if ((p = strchr (group, ':')))
                     *p = 0; /* We better strip any extra stuff. */
                   *group++ = 0;
                   if ((p = strchr (group, ':')))
                     *p = 0; /* We better strip any extra stuff. */
-                }                    
-              
-              fprintf (listfp, "k:%s:", my_percent_escape (key));
-              fprintf (listfp, "%s\n", group? my_percent_escape (group):"");
+                }
+
+              es_fprintf (listfp, "k:%s:", gc_percent_escape (key));
+              es_fprintf (listfp, "%s\n", group? gc_percent_escape (group):"");
             }
 
           /* All other lines are rule records.  */
             }
 
           /* All other lines are rule records.  */
-          fprintf (listfp, "r:::%s:%s:%s:",
-                   gc_component[component_id].name,                     
-                   option_info->name? option_info->name : "",
-                   flags? flags : "");
+          es_fprintf (listfp, "r:::%s:%s:%s:",
+                      gc_component[component_id].name,
+                      option_info->name? option_info->name : "",
+                      flags? flags : "");
           if (value != empty)
           if (value != empty)
-            fprintf (listfp, "\"%s", my_percent_escape (value));
-          
-          putc ('\n', listfp);
+            es_fprintf (listfp, "\"%s", gc_percent_escape (value));
+
+          es_putc ('\n', listfp);
         }
 
       /* Check whether the key matches but do this only if we are not
          running in syntax check mode. */
         }
 
       /* Check whether the key matches but do this only if we are not
          running in syntax check mode. */
-      if ( update 
+      if ( update
            && !result && !listfp
            && (got_match || (key && key_matches_user_or_group (key))) )
         {
            && !result && !listfp
            && (got_match || (key && key_matches_user_or_group (key))) )
         {
@@ -3382,10 +3903,7 @@ gc_process_gpgconf_conf (const char *fname_arg, int update, int defaults,
 
           if (defaults)
             {
 
           if (defaults)
             {
-              assert (component_id >= 0 && component_id < GC_COMPONENT_NR);
-              used_components[component_id] = 1;
-
-              /* Here we explicitly allow to update the value again.  */
+              /* Here we explicitly allow updating the value again.  */
               if (newflags)
                 {
                   option_info->new_flags = 0;
               if (newflags)
                 {
                   option_info->new_flags = 0;
@@ -3395,18 +3913,18 @@ gc_process_gpgconf_conf (const char *fname_arg, int update, int defaults,
                   xfree (option_info->new_value);
                   option_info->new_value = NULL;
                 }
                   xfree (option_info->new_value);
                   option_info->new_value = NULL;
                 }
-              change_one_value (option_info, runtime, newflags, value);
+              change_one_value (option_info, runtime, newflags, value, 0);
             }
         }
     }
 
             }
         }
     }
 
-  if (length < 0 || ferror (config))
+  if (length < 0 || gpgrt_ferror (config))
     {
     {
-      gc_error (0, errno, "error reading from `%s'", fname);
+      gc_error (0, errno, "error reading from '%s'", fname);
       result = -1;
     }
       result = -1;
     }
-  if (fclose (config) && ferror (config))
-    gc_error (0, errno, "error closing `%s'", fname);
+  if (gpgrt_fclose (config))
+    gc_error (0, errno, "error closing '%s'", fname);
 
   xfree (line);
 
 
   xfree (line);
 
@@ -3420,18 +3938,225 @@ gc_process_gpgconf_conf (const char *fname_arg, int update, int defaults,
 
       for (component_id = 0; component_id < GC_COMPONENT_NR; component_id++)
         {
 
       for (component_id = 0; component_id < GC_COMPONENT_NR; component_id++)
         {
-          gc_component_change_options (component_id, NULL);
+          gc_component_change_options (component_id, NULL, NULL, 0);
         }
       opt.runtime = save_opt_runtime;
 
       if (opt.runtime)
         {
         }
       opt.runtime = save_opt_runtime;
 
       if (opt.runtime)
         {
-          for (backend_id = 0; backend_id < GC_BACKEND_NR; backend_id++)  
+          for (backend_id = 0; backend_id < GC_BACKEND_NR; backend_id++)
             if (runtime[backend_id] && gc_backend[backend_id].runtime_change)
             if (runtime[backend_id] && gc_backend[backend_id].runtime_change)
-              (*gc_backend[backend_id].runtime_change) ();
+              (*gc_backend[backend_id].runtime_change) (0);
         }
     }
 
   xfree (fname);
   return result;
 }
         }
     }
 
   xfree (fname);
   return result;
 }
+
+
+/*
+ * Apply the profile FNAME to all known configure files.
+ */
+gpg_error_t
+gc_apply_profile (const char *fname)
+{
+  gpg_error_t err;
+  char *fname_buffer = NULL;
+  char *line = NULL;
+  size_t line_len = 0;
+  ssize_t length;
+  estream_t fp;
+  int lineno = 0;
+  int runtime[GC_BACKEND_NR];
+  int backend_id;
+  int component_id = -1;
+  int skip_section = 0;
+  int error_count = 0;
+  int newflags;
+
+  if (!fname)
+    fname = "-";
+
+  for (backend_id = 0; backend_id < GC_BACKEND_NR; backend_id++)
+    runtime[backend_id] = 0;
+
+
+  if (!(!strcmp (fname, "-")
+        || strchr (fname, '/')
+#ifdef HAVE_W32_SYSTEM
+        || strchr (fname, '\\')
+#endif
+        || strchr (fname, '.')))
+    {
+      /* FNAME looks like a standard profile name.  Check whether one
+       * is installed and use that instead of the given file name.  */
+      fname_buffer = xstrconcat (gnupg_datadir (), DIRSEP_S,
+                                 fname, ".prf", NULL);
+      if (!access (fname_buffer, F_OK))
+        fname = fname_buffer;
+    }
+
+  fp = !strcmp (fname, "-")? es_stdin : es_fopen (fname, "r");
+  if (!fp)
+    {
+      err = gpg_error_from_syserror ();
+      log_error ("can't open '%s': %s\n", fname, gpg_strerror (err));
+      return err;
+    }
+
+  if (opt.verbose)
+    log_info ("applying profile '%s'\n", fname);
+
+  err = 0;
+  while ((length = es_read_line (fp, &line, &line_len, NULL)) > 0)
+    {
+      char *name, *flags, *value;
+      gc_option_t *option_info = NULL;
+      char *p;
+
+      lineno++;
+      name = line;
+      while (*name == ' ' || *name == '\t')
+        name++;
+      if (!*name || *name == '#' || *name == '\r' || *name == '\n')
+        continue;
+      trim_trailing_spaces (name);
+
+      /* Check whether this is a new section.  */
+      if (*name == '[')
+        {
+          name++;
+          skip_section = 0;
+          /* New section: Get the name of the component.  */
+          p = strchr (name, ']');
+          if (!p)
+            {
+              error_count++;
+              log_info ("%s:%d:%d: error: syntax error in section tag\n",
+                        fname, lineno, (int)(name - line));
+              skip_section = 1;
+              continue;
+            }
+          *p++ = 0;
+          if (*p)
+            log_info ("%s:%d:%d: warning: garbage after section tag\n",
+                      fname, lineno, (int)(p - line));
+
+          trim_spaces (name);
+          component_id = gc_component_find (name);
+          if (component_id < 0)
+            {
+              log_info ("%s:%d:%d: warning: skipping unknown section '%s'\n",
+                        fname, lineno, (int)(name - line), name );
+              skip_section = 1;
+            }
+          continue;
+        }
+
+      if (skip_section)
+        continue;
+      if (component_id < 0)
+        {
+          error_count++;
+          log_info ("%s:%d:%d: error: not in a valid section\n",
+                    fname, lineno, (int)(name - line));
+          skip_section = 1;
+          continue;
+        }
+
+      /* Parse the option name.  */
+      for (p = name; *p && !spacep (p); p++)
+        ;
+      *p++ = 0;
+      value = p;
+
+      option_info = find_option (component_id, name, GC_BACKEND_ANY);
+      if (!option_info)
+        {
+          error_count++;
+          log_info ("%s:%d:%d: error: unknown option '%s' in section '%s'\n",
+                    fname, lineno, (int)(name - line),
+                    name, gc_component[component_id].name);
+          continue;
+        }
+
+      /* Parse the optional flags. */
+      trim_spaces (value);
+      flags = value;
+      if (*flags == '[')
+        {
+          flags++;
+          p = strchr (flags, ']');
+          if (!p)
+            {
+              log_info ("%s:%d:%d: warning: invalid flag specification\n",
+                        fname, lineno, (int)(p - line));
+              continue;
+            }
+          *p++ = 0;
+          value = p;
+          trim_spaces (value);
+        }
+      else /* No flags given.  */
+        flags = NULL;
+
+      /* Set required defaults.  */
+      if (gc_arg_type[option_info->arg_type].fallback == GC_ARG_TYPE_NONE
+          && !*value)
+        value = "1";
+
+      /* Check and save this option.  */
+      newflags = 0;
+      if (flags && !strcmp (flags, "default"))
+        newflags |= GC_OPT_FLAG_DEFAULT;
+
+      if (newflags)
+        option_info->new_flags = 0;
+      if (*value)
+        {
+          xfree (option_info->new_value);
+          option_info->new_value = NULL;
+        }
+      change_one_value (option_info, runtime, newflags, value, 1);
+    }
+
+  if (length < 0 || es_ferror (fp))
+    {
+      err = gpg_error_from_syserror ();
+      error_count++;
+      log_error (_("%s:%u: read error: %s\n"),
+                 fname, lineno, gpg_strerror (err));
+    }
+  if (es_fclose (fp))
+    log_error (_("error closing '%s'\n"), fname);
+  if (error_count)
+    log_error (_("error parsing '%s'\n"), fname);
+
+  xfree (line);
+
+  /* If it all worked, process the options. */
+  if (!err)
+    {
+      /* We need to switch off the runtime update, so that we can do
+         it later all at once. */
+      int save_opt_runtime = opt.runtime;
+      opt.runtime = 0;
+
+      for (component_id = 0; component_id < GC_COMPONENT_NR; component_id++)
+        {
+          gc_component_change_options (component_id, NULL, NULL, 1);
+        }
+      opt.runtime = save_opt_runtime;
+
+      if (opt.runtime)
+        {
+          for (backend_id = 0; backend_id < GC_BACKEND_NR; backend_id++)
+            if (runtime[backend_id] && gc_backend[backend_id].runtime_change)
+              (*gc_backend[backend_id].runtime_change) (0);
+        }
+    }
+
+  xfree (fname_buffer);
+  return err;
+}