Add global flags disable-gpgconf, gpgconf-name, and gpg-name.

* src/gpgme.c (gpgme_set_global_flag): Add names "disable-gpgconf",
"gpgconf-name", and "gpg-name".
* src/dirinfo.c (_gpgme_dirinfo_disable_gpgconf): New.
(get_gpgconf_item): Minor debug info change.
* src/posix-util.c (default_gpg_name, default_gpgconf_name): Add vars.
(_gpgme_set_default_gpg_name): New.
(_gpgme_set_default_gpgconf_name): New.
(_gpgme_get_gpg_path, _gpgme_get_gpgconf_path): Use new vars.
(walk_path): Add debug output on failure.
* src/w32-util.c (default_gpg_name, default_gpgconf_name): Add vars.
(replace_slashes): New.
(get_basename): New.
(_gpgme_set_default_gpg_name): New.
(_gpgme_set_default_gpgconf_name): New.
(_gpgme_get_gpg_path, _gpgme_get_gpgconf_path): Use new vars.

* tests/t-engine-info.c (main): Add --verbose and --set-global-flag
options.
--

Note that the Windows part has not been tested.
This commit is contained in:
Werner Koch 2014-01-06 17:16:52 +01:00
parent 02ba35c1b6
commit 6564e5e78e
8 changed files with 268 additions and 30 deletions

View File

@ -1,5 +1,5 @@
\input texinfo @c -*- mode: texinfo; coding: latin-1; -*- \input texinfo @c -*- mode: texinfo; coding: utf-8; -*-
@documentencoding ISO-8859-1 @documentencoding UTF-8
@setfilename gpgme.info @setfilename gpgme.info
@settitle The `GnuPG Made Easy' Reference Manual @settitle The `GnuPG Made Easy' Reference Manual
@ -14,7 +14,7 @@
@copying @copying
Copyright @copyright{} 2002, 2003, 2004, 2005, 2006, 2007, Copyright @copyright{} 2002, 2003, 2004, 2005, 2006, 2007,
2008, 2010, 2012, 2013 g10 Code GmbH. 2008, 2010, 2012, 2013, 2014 g10 Code GmbH.
@quotation @quotation
Permission is granted to copy, distribute and/or modify this document Permission is granted to copy, distribute and/or modify this document
@ -72,7 +72,7 @@ This is Edition @value{EDITION}, last updated @value{UPDATED}, of
@center for version @value{VERSION} @center for version @value{VERSION}
@page @page
@vskip 0pt plus 1filll @vskip 0pt plus 1filll
Published by g10 Code GmbH@* Hüttenstr. 61@* 40699 Erkrath, Germany Published by g10 Code GmbH@* Hüttenstr. 61@* 40699 Erkrath, Germany
@insertcopying @insertcopying
@end titlepage @end titlepage
@ -648,14 +648,39 @@ does not return a detailed error code).
On some systems it is not easy to set environment variables and thus On some systems it is not easy to set environment variables and thus
hard to use @acronym{GPGME}'s internal trace facility for debugging. hard to use @acronym{GPGME}'s internal trace facility for debugging.
This function has been introduced as an alternative way to enable This function has been introduced as an alternative way to enable
debugging. It is important to assure that only one thread accesses debugging and for a couple of other rarely used tweaks. It is
@acronym{GPGME} functions between a call to this function and after important to assure that only one thread accesses @acronym{GPGME}
the return from the call to @code{gpgme_check_version}. functions between a call to this function and after the return from
the call to @code{gpgme_check_version}.
To enable debugging, you need to call this function as early as All currently supported features require that this function is called
possible --- even before @code{gpgme_check_version} --- with the as early as possible --- even before @code{gpgme_check_version}. The
string ``debug'' for @var{name} and @var{value} identical to the value features are identified by the following values for @var{name}:
used with the environment variable @code{GPGME_DEBUG}.
@table @code
@item "debug"
To enable debugging use the string ``debug'' for @var{name} and
@var{value} identical to the value used with the environment variable
@code{GPGME_DEBUG}.
@item "disable-gpgconf"
Using this feature with any @var{value} disables the detection of the
gpgconf program and thus forces GPGME to fallback into the simple
OpenPGP only mode. It may be used to force the use of GnuPG-1 on
systems which have both GPG versions installed. Note that in general
the use of @code{gpgme_set_engine_info} is a better way to select a
specific engine version.
@item "gpgconf-name"
@itemx "gpg-name"
Set the name of the gpgconf respective gpg binary. The defaults are
@code{GNU/GnuPG/gpgconf} and @code{GNU/GnuPG/gpg}. Under Unix the
leading directory part is ignored. Under Windows the leading
directory part is used as the default installation directory; the
@code{.exe} suffix is added by GPGME. Use forward slashed even under
Windows.
@end table
This function returns @code{0} on success. In contrast to other This function returns @code{0} on success. In contrast to other
functions the non-zero return value on failure does not convey any functions the non-zero return value on failure does not convey any

View File

@ -48,6 +48,7 @@ enum
/* Values retrieved via gpgconf and cached here. */ /* Values retrieved via gpgconf and cached here. */
static struct { static struct {
int valid; /* Cached information is valid. */ int valid; /* Cached information is valid. */
int disable_gpgconf;
char *homedir; char *homedir;
char *agent_socket; char *agent_socket;
char *gpgconf_name; char *gpgconf_name;
@ -58,6 +59,15 @@ static struct {
} dirinfo; } dirinfo;
/* Helper function to be used only by gpgme_set_global_flag. */
void
_gpgme_dirinfo_disable_gpgconf (void)
{
dirinfo.disable_gpgconf = 1;
}
/* Parse the output of "gpgconf --list-dirs". This function expects /* Parse the output of "gpgconf --list-dirs". This function expects
that DIRINFO_LOCK is held by the caller. If COMPONENTS is set, the that DIRINFO_LOCK is held by the caller. If COMPONENTS is set, the
output of --list-components is expected. */ output of --list-components is expected. */
@ -198,16 +208,16 @@ get_gpgconf_item (int what)
{ {
char *pgmname; char *pgmname;
pgmname = _gpgme_get_gpgconf_path (); pgmname = dirinfo.disable_gpgconf? NULL : _gpgme_get_gpgconf_path ();
if (pgmname && access (pgmname, F_OK)) if (pgmname && access (pgmname, F_OK))
{ {
_gpgme_debug (DEBUG_INIT, _gpgme_debug (DEBUG_INIT,
"gpgme_dinfo: gpgconf='%s' [not installed]\n", pgmname); "gpgme-dinfo: gpgconf='%s' [not installed]\n", pgmname);
free (pgmname); free (pgmname);
pgmname = NULL; /* Not available. */ pgmname = NULL; /* Not available. */
} }
else else
_gpgme_debug (DEBUG_INIT, "gpgme_dinfo: gpgconf='%s'\n", _gpgme_debug (DEBUG_INIT, "gpgme-dinfo: gpgconf='%s'\n",
pgmname? pgmname : "[null]"); pgmname? pgmname : "[null]");
if (!pgmname) if (!pgmname)
{ {
@ -231,22 +241,22 @@ get_gpgconf_item (int what)
allocated. */ allocated. */
dirinfo.valid = 1; dirinfo.valid = 1;
if (dirinfo.gpg_name) if (dirinfo.gpg_name)
_gpgme_debug (DEBUG_INIT, "gpgme_dinfo: gpg='%s'\n", _gpgme_debug (DEBUG_INIT, "gpgme-dinfo: gpg='%s'\n",
dirinfo.gpg_name); dirinfo.gpg_name);
if (dirinfo.g13_name) if (dirinfo.g13_name)
_gpgme_debug (DEBUG_INIT, "gpgme_dinfo: g13='%s'\n", _gpgme_debug (DEBUG_INIT, "gpgme-dinfo: g13='%s'\n",
dirinfo.g13_name); dirinfo.g13_name);
if (dirinfo.gpgsm_name) if (dirinfo.gpgsm_name)
_gpgme_debug (DEBUG_INIT, "gpgme_dinfo: gpgsm='%s'\n", _gpgme_debug (DEBUG_INIT, "gpgme-dinfo: gpgsm='%s'\n",
dirinfo.gpgsm_name); dirinfo.gpgsm_name);
if (dirinfo.homedir) if (dirinfo.homedir)
_gpgme_debug (DEBUG_INIT, "gpgme_dinfo: homedir='%s'\n", _gpgme_debug (DEBUG_INIT, "gpgme-dinfo: homedir='%s'\n",
dirinfo.homedir); dirinfo.homedir);
if (dirinfo.agent_socket) if (dirinfo.agent_socket)
_gpgme_debug (DEBUG_INIT, "gpgme_dinfo: agent='%s'\n", _gpgme_debug (DEBUG_INIT, "gpgme-dinfo: agent='%s'\n",
dirinfo.agent_socket); dirinfo.agent_socket);
if (dirinfo.uisrv_socket) if (dirinfo.uisrv_socket)
_gpgme_debug (DEBUG_INIT, "gpgme_dinfo: uisrv='%s'\n", _gpgme_debug (DEBUG_INIT, "gpgme-dinfo: uisrv='%s'\n",
dirinfo.uisrv_socket); dirinfo.uisrv_socket);
} }
switch (what) switch (what)

View File

@ -37,6 +37,7 @@
#include "wait.h" #include "wait.h"
#include "debug.h" #include "debug.h"
#include "priv-io.h" #include "priv-io.h"
#include "sys-util.h"
/* The default locale. */ /* The default locale. */
@ -65,6 +66,15 @@ gpgme_set_global_flag (const char *name, const char *value)
return -1; return -1;
else if (!strcmp (name, "debug")) else if (!strcmp (name, "debug"))
return _gpgme_debug_set_debug_envvar (value); return _gpgme_debug_set_debug_envvar (value);
else if (!strcmp (name, "disable-gpgconf"))
{
_gpgme_dirinfo_disable_gpgconf ();
return 0;
}
else if (!strcmp (name, "gpgconf-name"))
return _gpgme_set_default_gpgconf_name (value);
else if (!strcmp (name, "gpg-name"))
return _gpgme_set_default_gpg_name (value);
else else
return -1; return -1;
} }

View File

@ -29,6 +29,46 @@
#include "util.h" #include "util.h"
#include "sys-util.h" #include "sys-util.h"
#include "debug.h"
/* These variables store the malloced name of alternative default
binaries. The are set only once by gpgme_set_global_flag. */
static char *default_gpg_name;
static char *default_gpgconf_name;
/* Set the default name for the gpg binary. This function may only be
called by gpgme_set_global_flag. Returns 0 on success. Leading
directories are removed from NAME. */
int
_gpgme_set_default_gpg_name (const char *name)
{
const char *s;
s = strrchr (name, '/');
if (s)
name = s + 1;
if (!default_gpg_name)
default_gpg_name = strdup (name);
return !default_gpg_name;
}
/* Set the default name for the gpgconf binary. This function may
only be called by gpgme_set_global_flag. Returns 0 on success.
Leading directories are removed from NAME. */
int
_gpgme_set_default_gpgconf_name (const char *name)
{
const char *s;
s = strrchr (name, '/');
if (s)
name = s + 1;
if (!default_gpgconf_name)
default_gpgconf_name = strdup (name);
return !default_gpgconf_name;
}
/* Find an executable program PGM along the envvar PATH. */ /* Find an executable program PGM along the envvar PATH. */
@ -60,6 +100,9 @@ walk_path (const char *pgm)
path = s + 1; path = s + 1;
} }
_gpgme_debug (DEBUG_ENGINE, "gpgme-walk_path: '%s' not found in '%s'",
pgm, path);
free (fname); free (fname);
return NULL; return NULL;
} }
@ -72,7 +115,7 @@ walk_path (const char *pgm)
char * char *
_gpgme_get_gpg_path (void) _gpgme_get_gpg_path (void)
{ {
return walk_path ("gpg"); return walk_path (default_gpg_name? default_gpg_name : "gpg");
} }
@ -81,7 +124,7 @@ _gpgme_get_gpg_path (void)
char * char *
_gpgme_get_gpgconf_path (void) _gpgme_get_gpgconf_path (void)
{ {
return walk_path ("gpgconf"); return walk_path (default_gpgconf_name? default_gpgconf_name : "gpgconf");
} }
/* See w32-util.c */ /* See w32-util.c */

View File

@ -21,6 +21,9 @@
#define SYS_UTIL_H #define SYS_UTIL_H
/*-- {posix,w32}-util.c --*/ /*-- {posix,w32}-util.c --*/
int _gpgme_set_default_gpg_name (const char *name);
int _gpgme_set_default_gpgconf_name (const char *name);
char *_gpgme_get_gpg_path (void); char *_gpgme_get_gpg_path (void);
char *_gpgme_get_gpgconf_path (void); char *_gpgme_get_gpgconf_path (void);

View File

@ -51,6 +51,8 @@ int _gpgme_get_conf_int (const char *key, int *value);
void _gpgme_allow_set_foreground_window (pid_t pid); void _gpgme_allow_set_foreground_window (pid_t pid);
/*-- dirinfo.c --*/ /*-- dirinfo.c --*/
void _gpgme_dirinfo_disable_gpgconf (void);
const char *_gpgme_get_default_homedir (void); const char *_gpgme_get_default_homedir (void);
const char *_gpgme_get_default_agent_socket (void); const char *_gpgme_get_default_agent_socket (void);
const char *_gpgme_get_default_gpg_name (void); const char *_gpgme_get_default_gpg_name (void);

View File

@ -81,6 +81,11 @@ DEFINE_STATIC_LOCK (get_path_lock);
file name of the DLL or executable which contains the gpgme code. */ file name of the DLL or executable which contains the gpgme code. */
static HMODULE my_hmodule; static HMODULE my_hmodule;
/* These variables store the malloced name of alternative default
binaries. The are set only once by gpgme_set_global_flag. */
static char *default_gpg_name;
static char *default_gpgconf_name;
#ifdef HAVE_ALLOW_SET_FOREGROUND_WINDOW #ifdef HAVE_ALLOW_SET_FOREGROUND_WINDOW
@ -151,6 +156,32 @@ wchar_to_utf8 (const wchar_t *string)
} }
/* Replace all forward slashes by backslashes. */
static void
replace_slashes (char *string)
{
for (; *string; string++)
if (*string == '/')
*string = '\\';
}
/* Get the base name of NAME. Returns a pointer into NAME right after
the last slash or backslash or to NAME if no slash or backslash
exists. */
static const char *
get_basename (const char *name)
{
const char *mark, *s;
for (mark=NULL, s=name; *s; s++)
if (*s == '/' || *s == '\\')
mark = s;
return mark? mark+1 : name;
}
void void
_gpgme_allow_set_foreground_window (pid_t pid) _gpgme_allow_set_foreground_window (pid_t pid)
{ {
@ -373,7 +404,7 @@ find_program_in_inst_dir (const char *inst_dir, const char *name)
char *dir; char *dir;
/* If an installation directory has been passed, this overrides a /* If an installation directory has been passed, this overrides a
location given bu the registry. The idea here is that we prefer location given by the registry. The idea here is that we prefer
a program installed alongside with gpgme. We don't want the a program installed alongside with gpgme. We don't want the
registry to override this to have a better isolation of an gpgme registry to override this to have a better isolation of an gpgme
aware applications for other effects. Note that the "Install aware applications for other effects. Note that the "Install
@ -424,6 +455,41 @@ find_program_at_standard_place (const char *name)
} }
/* Set the default name for the gpg binary. This function may only be
called by gpgme_set_global_flag. Returns 0 on success. */
int
_gpgme_set_default_gpg_name (const char *name)
{
if (!default_gpg_name)
{
default_gpg_name = malloc (strlen (name) + 5);
if (default_gpg_name)
{
strcpy (stpcpy (default_gpg_name, name), ".exe");
replace_slashes (default_gpg_name);
}
}
return !default_gpg_name;
}
/* Set the default name for the gpgconf binary. This function may only be
called by gpgme_set_global_flag. Returns 0 on success. */
int
_gpgme_set_default_gpgconf_name (const char *name)
{
if (!default_gpgconf_name)
{
default_gpgconf_name = malloc (strlen (name) + 5);
if (default_gpgconf_name)
{
strcpy (stpcpy (default_gpgconf_name, name), ".exe");
replace_slashes (default_gpgconf_name);
}
}
return !default_gpgconf_name;
}
/* Return the full file name of the GPG binary. This function is used /* Return the full file name of the GPG binary. This function is used
if gpgconf was not found and thus it can be assumed that gpg2 is if gpgconf was not found and thus it can be assumed that gpg2 is
not installed. This function is only called by get_gpgconf_item not installed. This function is only called by get_gpgconf_item
@ -432,27 +498,47 @@ char *
_gpgme_get_gpg_path (void) _gpgme_get_gpg_path (void)
{ {
char *gpg; char *gpg;
const char *inst_dir; const char *inst_dir, *name;
inst_dir = _gpgme_get_inst_dir (); inst_dir = _gpgme_get_inst_dir ();
gpg = find_program_in_inst_dir (inst_dir, "gpg.exe"); gpg = find_program_in_inst_dir
(inst_dir,
default_gpg_name? get_basename (default_gpg_name) : "gpg.exe");
if (!gpg) if (!gpg)
gpg = find_program_at_standard_place ("GNU\\GnuPG\\gpg.exe"); {
name = (default_gpg_name? default_gpg_name
/* */ : "GNU\\GnuPG\\gpg.exe");
gpg = find_program_at_standard_place (name);
if (!gpg)
_gpgme_debug (DEBUG_ENGINE, "_gpgme_get_gpg_path: '%s' not found",
name);
}
return gpg; return gpg;
} }
/* This function is only called by get_gpgconf_item and may not be /* This function is only called by get_gpgconf_item and may not be
called concurrently. */ called concurrently. */
char * char *
_gpgme_get_gpgconf_path (void) _gpgme_get_gpgconf_path (void)
{ {
char *gpgconf; char *gpgconf;
const char *inst_dir; const char *inst_dir, *name;
inst_dir = _gpgme_get_inst_dir (); inst_dir = _gpgme_get_inst_dir ();
gpgconf = find_program_in_inst_dir (inst_dir, "gpgconf.exe"); gpgconf = find_program_in_inst_dir
(inst_dir,
default_gpgconf_name? get_basename (default_gpgconf_name) : "gpgconf.exe");
if (!gpgconf) if (!gpgconf)
gpgconf = find_program_at_standard_place ("GNU\\GnuPG\\gpgconf.exe"); {
name = (default_gpgconf_name? default_gpgconf_name
/* */ : "GNU\\GnuPG\\gpgconf.exe");
gpgconf = find_program_at_standard_place (name);
if (!gpgconf)
_gpgme_debug (DEBUG_ENGINE, "_gpgme_get_gpgconf_path: '%s' not found",
name);
}
return gpgconf; return gpgconf;
} }

View File

@ -28,6 +28,12 @@
#include <gpgme.h> #include <gpgme.h>
#define PGM "t-engine-info"
static int verbose;
#define fail_if_err(err) \ #define fail_if_err(err) \
do \ do \
@ -42,13 +48,66 @@
while (0) while (0)
int int
main (int argc, char **argv ) main (int argc, char **argv )
{ {
int last_argc = -1;
gpgme_engine_info_t info; gpgme_engine_info_t info;
gpgme_error_t err; gpgme_error_t err;
if (argc)
{ argc--; argv++; }
while (argc && last_argc != argc )
{
last_argc = argc;
if (!strcmp (*argv, "--"))
{
argc--; argv++;
break;
}
else if (!strcmp (*argv, "--help"))
{
fputs ("usage: " PGM " [options]\n"
"Options:\n"
" --set-global-flag KEY VALUE\n",
stdout);
exit (0);
}
else if (!strcmp (*argv, "--verbose"))
{
verbose++;
argc--; argv++;
}
else if (!strcmp (*argv, "--set-global-flag"))
{
argc--; argv++;
if (argc < 2)
{
fprintf (stderr, PGM ": not enough arguments for option\n");
exit (1);
}
if (gpgme_set_global_flag (argv[0], argv[1]))
{
fprintf (stderr, PGM ": gpgme_set_global_flag failed\n");
exit (1);
}
argc--; argv++;
argc--; argv++;
}
else if (!strncmp (*argv, "--", 2))
{
fprintf (stderr, PGM ": unknown option '%s'\n", *argv);
exit (1);
}
}
if (argc)
{
fprintf (stderr, PGM ": unexpected arguments\n");
exit (1);
}
gpgme_check_version (NULL); gpgme_check_version (NULL);
err = gpgme_get_engine_info (&info); err = gpgme_get_engine_info (&info);
fail_if_err (err); fail_if_err (err);