doc/
authorMarcus Brinkmann <mb@g10code.com>
Mon, 19 May 2008 22:46:41 +0000 (22:46 +0000)
committerMarcus Brinkmann <mb@g10code.com>
Mon, 19 May 2008 22:46:41 +0000 (22:46 +0000)
2008-05-20  Marcus Brinkmann  <marcus@g10code.de>

* tools.texi (Invoking gpgconf): Add --dry-run and --check-options.
(Checking programs): Document --check-options.

tools/
2008-05-20  Marcus Brinkmann  <marcus@g10code.de>

* gpgconf.h (gc_component_check_programs): Rename to ...
(gc_check_programs): ... this.
(gc_component_change_options): Add argument OUT.
(gc_component_check_options): New function.
* gpgconf.c (enum cmd_and_opt_values): New option aCheckOptions.
(opts): Add new option aCheckOptions (aka --check-options).
(main): Handle new option aCheckOptions.
* gpgconf-comp.c (gc_component_check_programs): Rename to ...
(gc_check_programs): ... this.  Refactor core of it to ...
(gc_component_check_options): ... this new function.
(gc_component_change_options): Add new argument OUT.  Externally
verify all changes.  Implement option --dry-run.

doc/ChangeLog
doc/tools.texi
tools/ChangeLog
tools/gpgconf-comp.c
tools/gpgconf.c
tools/gpgconf.h

index d083a9b..cd2f616 100644 (file)
@@ -1,3 +1,8 @@
+2008-05-20  Marcus Brinkmann  <marcus@g10code.de>
+
+       * tools.texi (Invoking gpgconf): Add --dry-run and --check-options.
+       (Checking programs): Document --check-options.
+
 2008-05-15  Marcus Brinkmann  <marcus@g10code.de>
 
        * gpg.texi (Operational GPG Commands): Mention the way to change
 2008-05-15  Marcus Brinkmann  <marcus@g10code.de>
 
        * gpg.texi (Operational GPG Commands): Mention the way to change
index 79a909d..888012e 100644 (file)
@@ -230,6 +230,9 @@ List all options of the component @var{component}.
 @item --change-options @var{component}
 Change the options of the component @var{component}.
 
 @item --change-options @var{component}
 Change the options of the component @var{component}.
 
+@item --check-options @var{component}
+Check the options for the component @var{component}.
+
 @item --apply-defaults
 Update all configuration files with values taken from the global
 configuration file (usually @file{/etc/gnupg/gpgconf.conf}).
 @item --apply-defaults
 Update all configuration files with values taken from the global
 configuration file (usually @file{/etc/gnupg/gpgconf.conf}).
@@ -260,11 +263,10 @@ The following options may be used:
 Outputs additional information while running.  Specifically, this
 extends numerical field values by human-readable descriptions.
 
 Outputs additional information while running.  Specifically, this
 extends numerical field values by human-readable descriptions.
 
-@c FIXME: Not yet supported.
-@c @item -n
-@c @itemx --dry-run
-@c Do not actually change anything.  Useful together with
-@c @code{--change-options} for testing purposes.
+@item -n
+@itemx --dry-run
+Do not actually change anything.  This is currently only implemented
+for @code{--change-options} and can be used for testing purposes.
 
 @item -r
 @itemx --runtime
 
 @item -r
 @itemx --runtime
@@ -531,6 +533,11 @@ gpgsm:GPG for S/MIME:/usr/local/bin/gpgsm:1:1:
 dirmngr:Directory Manager:/usr/local/bin/dirmngr:0:0:
 @end example
 
 dirmngr:Directory Manager:/usr/local/bin/dirmngr:0:0:
 @end example
 
+@noindent
+The command @w{@code{--check-options @var{component}}} will verify the
+configuration file in the same manner as @code{--check-programs}, but
+only for the component @var{component}.
+
 
 @node Listing options
 @subsection Listing options
 
 @node Listing options
 @subsection Listing options
@@ -769,6 +776,10 @@ argument is used (only allowed if the argument is optional for this
 option).  Otherwise, the option will be set to the specified value.
 @end table
 
 option).  Otherwise, the option will be set to the specified value.
 @end table
 
+@noindent
+The output of the command is the same as that of
+@code{--check-options} for the modified configuration file.
+
 Examples:
 
 To set the force option, which is of basic type @code{none (0)}:
 Examples:
 
 To set the force option, which is of basic type @code{none (0)}:
index 6638be5..a28b774 100644 (file)
@@ -1,3 +1,18 @@
+2008-05-20  Marcus Brinkmann  <marcus@g10code.de>
+
+       * gpgconf.h (gc_component_check_programs): Rename to ...
+       (gc_check_programs): ... this.
+       (gc_component_change_options): Add argument OUT.
+       (gc_component_check_options): New function.
+       * gpgconf.c (enum cmd_and_opt_values): New option aCheckOptions.
+       (opts): Add new option aCheckOptions (aka --check-options).
+       (main): Handle new option aCheckOptions.
+       * gpgconf-comp.c (gc_component_check_programs): Rename to ...
+       (gc_check_programs): ... this.  Refactor core of it to ...
+       (gc_component_check_options): ... this new function.
+       (gc_component_change_options): Add new argument OUT.  Externally
+       verify all changes.  Implement option --dry-run.
+
 2008-05-09  Werner Koch  <wk@g10code.com>
 
        * gpgconf-comp.c (my_dgettext) [USE_SIMPLE_GETTEXT]:  Hack to
 2008-05-09  Werner Koch  <wk@g10code.com>
 
        * gpgconf-comp.c (my_dgettext) [USE_SIMPLE_GETTEXT]:  Hack to
index 664589b..5dc32d6 100644 (file)
@@ -1317,118 +1317,140 @@ collect_error_output (int fd, const char *tag)
 }
 
 
 }
 
 
-
-/* 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, FILE *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;
   int filedes[2];
   pid_t pid;
   int exitcode;
   int filedes[2];
-  error_line_t errlines, errptr;
+  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.  */
 
   /* 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;
+    }
+  argv[i++] = "--gpgconf-test";
+  argv[i++] = 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;  
+  
+  if (out)
+    {
+      const char *desc;
+      error_line_t errptr;
+
+      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);
+    }
 
 
-      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  */
-        }
-    } 
+  while (errlines)
+    {
+      error_line_t tmp = errlines->next;
+      xfree (errlines);
+      errlines = tmp;
+    }
+
+  return result;
+}
+
+
+/* Check all components that are available.  */
+void
+gc_check_programs (FILE *out)
+{
+  gc_component_t component;
+
+  for (component = 0; component < GC_COMPONENT_NR; component++)
+    gc_component_check_options (component, out, NULL);
 }
 
 
 }
 
 
@@ -2831,7 +2853,7 @@ change_one_value (gc_option_t *option, int *runtime,
    modifications are expected to already have been set to the global
    table. */
 void
    modifications are expected to already have been set to the global
    table. */
 void
-gc_component_change_options (int component, FILE *in)
+gc_component_change_options (int component, FILE *in, FILE *out)
 {
   int err = 0;
   int runtime[GC_BACKEND_NR];
 {
   int err = 0;
   int runtime[GC_BACKEND_NR];
@@ -2935,10 +2957,26 @@ 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_pathname[option->backend],
+                                       &dest_pathname[option->backend],
+                                       &orig_pathname[option->backend]);
+         if (! err)
+           {
+             /* External verification.  */
+             err = gc_component_check_options (component, out,
+                                               src_pathname[option->backend]);
+             if (err)
+               {
+                 gc_error (0, 0,
+                           _("External verification of component %s failed"),
+                           gc_component[component].name);
+                 errno = EINVAL;
+               }
+           }
+
+       }
       else
        err = change_options_file (component, option->backend,
                                   &src_pathname[option->backend],
       else
        err = change_options_file (component, option->backend,
                                   &src_pathname[option->backend],
@@ -2951,7 +2989,7 @@ gc_component_change_options (int component, FILE *in)
       option++;
     }
 
       option++;
     }
 
-  if (!err)
+  if (! err && ! opt.dry_run)
     {
       int i;
 
     {
       int i;
 
@@ -2994,12 +3032,12 @@ gc_component_change_options (int component, FILE *in)
        }
     }
 
        }
     }
 
-  if (err)
+  if (err || opt.dry_run)
     {
       int i;
       int saved_errno = errno;
 
     {
       int i;
       int saved_errno = errno;
 
-      /* An error occured.  */
+      /* An error occured or a dry-run is requested.  */
       for (i = 0; i < GC_BACKEND_NR; i++)
        {
          if (src_pathname[i])
       for (i = 0; i < GC_BACKEND_NR; i++)
        {
          if (src_pathname[i])
@@ -3027,7 +3065,11 @@ gc_component_change_options (int component, FILE *in)
                unlink (dest_pathname[i]);
            }
        }
                unlink (dest_pathname[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 it all worked, notify the daemons of the changes.  */
@@ -3055,6 +3097,7 @@ gc_component_change_options (int component, FILE *in)
        rename (orig_pathname[backend], backup_pathname);
       }
 
        rename (orig_pathname[backend], backup_pathname);
       }
 
+ leave:
   xfree (line);
 }
 
   xfree (line);
 }
 
@@ -3463,7 +3506,7 @@ 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);
         }
       opt.runtime = save_opt_runtime;
 
         }
       opt.runtime = save_opt_runtime;
 
index 9c1c77a..8813d54 100644 (file)
@@ -43,6 +43,7 @@ enum cmd_and_opt_values
     aCheckPrograms,
     aListOptions,
     aChangeOptions,
     aCheckPrograms,
     aListOptions,
     aChangeOptions,
+    aCheckOptions,
     aApplyDefaults,
     aListConfig,
     aCheckConfig
     aApplyDefaults,
     aListConfig,
     aCheckConfig
@@ -59,6 +60,7 @@ static ARGPARSE_OPTS opts[] =
     { aCheckPrograms, "check-programs", 256, N_("check all programs") },
     { aListOptions, "list-options", 256, N_("|COMPONENT|list options") },
     { aChangeOptions, "change-options", 256, N_("|COMPONENT|change options") },
     { aCheckPrograms, "check-programs", 256, N_("check all programs") },
     { aListOptions, "list-options", 256, N_("|COMPONENT|list options") },
     { aChangeOptions, "change-options", 256, N_("|COMPONENT|change options") },
+    { aCheckOptions, "check-options", 256, N_("|COMPONENT|check options") },
     { aApplyDefaults, "apply-defaults", 256,
       N_("apply global default values") },
     { aListConfig,   "list-config", 256,
     { aApplyDefaults, "apply-defaults", 256,
       N_("apply global default values") },
     { aListConfig,   "list-config", 256,
@@ -167,6 +169,7 @@ main (int argc, char **argv)
         case aCheckPrograms:
         case aListOptions:
         case aChangeOptions:
         case aCheckPrograms:
         case aListOptions:
         case aChangeOptions:
+        case aCheckOptions:
         case aApplyDefaults:
         case aListConfig:
         case aCheckConfig:
         case aApplyDefaults:
         case aListConfig:
         case aCheckConfig:
@@ -192,11 +195,12 @@ main (int argc, char **argv)
 
     case aCheckPrograms:
       /* Check all programs. */
 
     case aCheckPrograms:
       /* Check all programs. */
-      gc_component_check_programs (get_outfp (&outfp));
+      gc_check_programs (get_outfp (&outfp));
       break;
 
     case aListOptions:
     case aChangeOptions:
       break;
 
     case aListOptions:
     case aChangeOptions:
+    case aCheckOptions:
       if (!fname)
        {
          fputs (_("usage: gpgconf [options] "), stderr);
       if (!fname)
        {
          fputs (_("usage: gpgconf [options] "), stderr);
@@ -219,8 +223,10 @@ main (int argc, char **argv)
             exit (1);
          if (cmd == aListOptions)
            gc_component_list_options (idx, get_outfp (&outfp));
             exit (1);
          if (cmd == aListOptions)
            gc_component_list_options (idx, get_outfp (&outfp));
+         else if (cmd == aChangeOptions)
+            gc_component_change_options (idx, stdin, get_outfp (&outfp));
          else
          else
-            gc_component_change_options (idx, stdin);
+           gc_component_check_options (idx, get_outfp (&outfp), NULL);
        }
       break;
 
        }
       break;
 
index 2f4bd52..0a27dd9 100644 (file)
@@ -43,7 +43,7 @@ void gc_error (int status, int errnum, const char *fmt, ...);
 void gc_component_list_components (FILE *out);
 
 /* List all programs along with their status.  */
 void gc_component_list_components (FILE *out);
 
 /* List all programs along with their status.  */
-void gc_component_check_programs (FILE *out);
+void gc_check_programs (FILE *out);
 
 /* Find the component with the name NAME.  Returns -1 if not
    found.  */
 
 /* Find the component with the name NAME.  Returns -1 if not
    found.  */
@@ -57,7 +57,12 @@ void gc_component_retrieve_options (int component);
 void gc_component_list_options (int component, FILE *out);
 
 /* Read the modifications from IN and apply them.  */
 void gc_component_list_options (int component, FILE *out);
 
 /* Read the modifications from IN and apply them.  */
-void gc_component_change_options (int component, FILE *in);
+void gc_component_change_options (int component, FILE *in, FILE *out);
+
+/* Check the options of a single component.  Returns 0 if everything
+   is OK.  */
+int gc_component_check_options (int component, FILE *out,
+                               const char *conf_file);
 
 /* Process global configuration file.  */
 int gc_process_gpgconf_conf (const char *fname, int update, int defaults,
 
 /* Process global configuration file.  */
 int gc_process_gpgconf_conf (const char *fname, int update, int defaults,