common: Support locating components in the build tree.
authorJustus Winter <justus@g10code.com>
Wed, 14 Dec 2016 13:18:22 +0000 (14:18 +0100)
committerJustus Winter <justus@g10code.com>
Wed, 14 Dec 2016 15:41:18 +0000 (16:41 +0100)
* common/homedir.c (gnupg_build_directory): New variable.
(gnupg_module_name_called): Likewise.
(gnupg_set_builddir): New function.
(gnupg_set_builddir_from_env): Likewise.
(gnupg_module_name): Support locating components in the build tree.
* common/util.h (gnupg_set_builddir): New prototype.
* tests/openpgp/defs.scm (tools): Drop 'gpg and 'gpg-agent.
(tool): Rename to 'tool-hardcoded.
(gpg-conf): New function, with accessors for the results.
(gpg-components): New variable.
(tool): New function.
* tools/gpgconf.c (enum cmd_and_opt_values): New key.
(opts): New option '--build-prefix'.
(main): Handle new option.
--

This change makes sure that the components from the build tree are
used, and not some older installed version in PATH.  It also lets us
make GPGME use components from the build tree, making it possible to
execute GPGME's test suite with them.

Signed-off-by: Justus Winter <justus@g10code.com>
common/homedir.c
common/util.h
tests/openpgp/defs.scm
tools/gpgconf.c

index 59b7135..6b40bb6 100644 (file)
@@ -884,15 +884,60 @@ get_default_pinentry_name (int reset)
 }
 
 
+/* If set, 'gnupg_module_name' returns modules from that build
+ * directory.  */
+static char *gnupg_build_directory;
+
+/* For sanity checks.  */
+static int gnupg_module_name_called;
+
+
+/* Set NEWDIR as the new build directory.  This will make
+ * 'gnupg_module_name' return modules from that build directory.  Must
+ * be called before any invocation of 'gnupg_module_name', and must
+ * not be called twice.  It can be used by test suites to make sure
+ * the components from the build directory are used instead of
+ * potentially outdated installed ones.  */
+void
+gnupg_set_builddir (const char *newdir)
+{
+  log_assert (! gnupg_module_name_called);
+  log_assert (! gnupg_build_directory);
+  gnupg_build_directory = xtrystrdup (newdir);
+}
+
+
+/* If no build directory has been configured, try to set it from the
+ * environment.  We only do this in development builds to avoid
+ * increasing the set of influential environment variables and hence
+ * the attack surface of production builds.  */
+static void
+gnupg_set_builddir_from_env (void)
+{
+#ifdef IS_DEVELOPMENT_VERSION
+  if (gnupg_build_directory)
+    return;
+
+  gnupg_build_directory = getenv ("GNUPG_BUILDDIR");
+#endif
+}
+
+
 /* Return the file name of a helper tool.  WHICH is one of the
    GNUPG_MODULE_NAME_foo constants.  */
 const char *
 gnupg_module_name (int which)
 {
-#define X(a,b) do {                                                     \
+  gnupg_set_builddir_from_env ();
+  gnupg_module_name_called = 1;
+
+#define X(a,b,c) do {                                                   \
     static char *name;                                                  \
     if (!name)                                                          \
-      name = xstrconcat (gnupg_ ## a (), DIRSEP_S b EXEEXT_S, NULL);    \
+      name = gnupg_build_directory                                      \
+        ? xstrconcat (gnupg_build_directory,                            \
+                      DIRSEP_S b DIRSEP_S c EXEEXT_S, NULL)             \
+        : xstrconcat (gnupg_ ## a (), DIRSEP_S c EXEEXT_S, NULL);       \
     return name;                                                        \
   } while (0)
 
@@ -902,7 +947,7 @@ gnupg_module_name (int which)
 #ifdef GNUPG_DEFAULT_AGENT
       return GNUPG_DEFAULT_AGENT;
 #else
-      X(bindir, "gpg-agent");
+      X(bindir, "agent", "gpg-agent");
 #endif
 
     case GNUPG_MODULE_NAME_PINENTRY:
@@ -916,55 +961,57 @@ gnupg_module_name (int which)
 #ifdef GNUPG_DEFAULT_SCDAEMON
       return GNUPG_DEFAULT_SCDAEMON;
 #else
-      X(libexecdir, "scdaemon");
+      X(libexecdir, "scd", "scdaemon");
 #endif
 
     case GNUPG_MODULE_NAME_DIRMNGR:
 #ifdef GNUPG_DEFAULT_DIRMNGR
       return GNUPG_DEFAULT_DIRMNGR;
 #else
-      X(bindir, DIRMNGR_NAME);
+      X(bindir, "dirmngr", DIRMNGR_NAME);
 #endif
 
     case GNUPG_MODULE_NAME_PROTECT_TOOL:
 #ifdef GNUPG_DEFAULT_PROTECT_TOOL
       return GNUPG_DEFAULT_PROTECT_TOOL;
 #else
-      X(libexecdir, "gpg-protect-tool");
+      X(libexecdir, "agent", "gpg-protect-tool");
 #endif
 
     case GNUPG_MODULE_NAME_DIRMNGR_LDAP:
 #ifdef GNUPG_DEFAULT_DIRMNGR_LDAP
       return GNUPG_DEFAULT_DIRMNGR_LDAP;
 #else
-      X(libexecdir, "dirmngr_ldap");
+      X(libexecdir, "dirmngr", "dirmngr_ldap");
 #endif
 
     case GNUPG_MODULE_NAME_CHECK_PATTERN:
-      X(libexecdir, "gpg-check-pattern");
+      X(libexecdir, "tools", "gpg-check-pattern");
 
     case GNUPG_MODULE_NAME_GPGSM:
-      X(bindir, "gpgsm");
+      X(bindir, "sm", "gpgsm");
 
     case GNUPG_MODULE_NAME_GPG:
 #if USE_GPG2_HACK
-      X(bindir, GPG_NAME "2");
-#else
-      X(bindir, GPG_NAME);
+      if (! gnupg_build_directory)
+        X(bindir, "g10", GPG_NAME "2");
+      else
 #endif
+        X(bindir, "g10", GPG_NAME);
 
     case GNUPG_MODULE_NAME_GPGV:
 #if USE_GPG2_HACK
-      X(bindir, GPG_NAME "v2");
-#else
-      X(bindir, GPG_NAME "v");
+      if (! gnupg_build_directory)
+        X(bindir, "g10", GPG_NAME "v2");
+      else
 #endif
+        X(bindir, "g10", GPG_NAME "v");
 
     case GNUPG_MODULE_NAME_CONNECT_AGENT:
-      X(bindir, "gpg-connect-agent");
+      X(bindir, "tools", "gpg-connect-agent");
 
     case GNUPG_MODULE_NAME_GPGCONF:
-      X(bindir, "gpgconf");
+      X(bindir, "tools", "gpgconf");
 
     default:
       BUG ();
index 2ff2bbc..f7a53e1 100644 (file)
@@ -263,6 +263,7 @@ char *_gnupg_socketdir_internal (int skip_checks, unsigned *r_info);
 #define GNUPG_MODULE_NAME_GPGV          12
 const char *gnupg_module_name (int which);
 void gnupg_module_name_flush_some (void);
+void gnupg_set_builddir (const char *newdir);
 
 
 
index 5249ca9..ef81f99 100644 (file)
@@ -56,9 +56,7 @@
        value)))
 
 (define tools
-  '((gpg "GPG" "g10/gpg")
-    (gpgv "GPGV" "g10/gpgv")
-    (gpg-agent "GPG_AGENT" "agent/gpg-agent")
+  '((gpgv "GPGV" "g10/gpgv")
     (gpg-connect-agent "GPG_CONNECT_AGENT" "tools/gpg-connect-agent")
     (gpgconf "GPGCONF" "tools/gpgconf")
     (gpg-preset-passphrase "GPG_PRESET_PASSPHRASE"
@@ -67,7 +65,7 @@
     (gpg-zip "GPGZIP" "tools/gpg-zip")
     (pinentry "PINENTRY" "tests/openpgp/fake-pinentry")))
 
-(define (tool which)
+(define (tool-hardcoded which)
   (let ((t (assoc which tools))
        (prefix (getenv "BIN_PREFIX")))
     (getenv' (cadr t)
                          (string-append (getenv "objdir") "/" (caddr t))
                          (string-append prefix "/" (basename (caddr t))))))))
 
+(define (gpg-conf . args)
+  (let ((s (call-popen `(,(tool-hardcoded 'gpgconf) ,@args) "")))
+    (map (lambda (line) (string-split line #\:))
+        (string-split-newlines s))))
+(define :gc:c:name car)
+(define :gc:c:description cadr)
+(define :gc:c:pgmname caddr)
+
+(setenv "GNUPG_BUILDDIR" (getenv "objdir") #t)
+(define gpg-components (gpg-conf '--build-prefix (getenv "objdir")
+                                '--list-components))
+
+(define (tool which)
+  (case which
+    ((gpg gpg-agent scdaemon gpgsm dirmngr)
+     (:gc:c:pgmname (assoc (symbol->string which) gpg-components)))
+    (else
+     (tool-hardcoded which))))
 
 (define (gpg-has-option? option)
   (string-contains? (call-popen `(,(tool 'gpg) --dump-options) "")
index 5f7912a..d056f4f 100644 (file)
@@ -44,6 +44,7 @@ enum cmd_and_opt_values
     oNull       = '0',
     oNoVerbose = 500,
     oHomedir,
+    oBuilddir,
 
     aListComponents,
     aCheckPrograms,
@@ -98,6 +99,7 @@ static ARGPARSE_OPTS opts[] =
     { oRuntime, "runtime",  0, N_("activate changes at runtime, if possible") },
     /* hidden options */
     { oHomedir, "homedir", 2, "@" },
+    { oBuilddir, "build-prefix", 2, "@" },
     { oNull, "null", 0, "@" },
     { oNoVerbose, "no-verbose",  0, "@"},
     {0}
@@ -483,6 +485,7 @@ main (int argc, char **argv)
         case oVerbose:   opt.verbose++; break;
         case oNoVerbose: opt.verbose = 0; break;
         case oHomedir:   gnupg_set_homedir (pargs.r.ret_str); break;
+        case oBuilddir:  gnupg_set_builddir (pargs.r.ret_str); break;
         case oNull:      opt.null = 1; break;
 
        case aListDirs: