2004-01-31 Marcus Brinkmann <marcus@g10code.de>
authorMarcus Brinkmann <mb@g10code.com>
Sat, 31 Jan 2004 13:58:27 +0000 (13:58 +0000)
committerMarcus Brinkmann <mb@g10code.com>
Sat, 31 Jan 2004 13:58:27 +0000 (13:58 +0000)
* gpgconf-comp.c: Some bug fixes, parse only defaults from the
program, and read the current values from the configuration file
directly.

tools/ChangeLog
tools/gpgconf-comp.c

index 1d21812..110a434 100644 (file)
@@ -1,3 +1,9 @@
+2004-01-31  Marcus Brinkmann  <marcus@g10code.de>
+
+       * gpgconf-comp.c: Some bug fixes, parse only defaults from the
+       program, and read the current values from the configuration file
+       directly.
+
 2004-01-30  Marcus Brinkmann  <marcus@g10code.de>
 
        * gpgconf-comp.c (gc_error): New function, use it instead of
index a6bda07..fc3d4ed 100644 (file)
@@ -1,5 +1,5 @@
 /* gpgconf-comp.c - Configuration utility for GnuPG.
-   Copyright (C) 2003 g10 Code GmbH
+   Copyright (C) 2004 g10 Code GmbH
 
    This file is part of GnuPG.
  
@@ -143,10 +143,10 @@ static struct
 } gc_backend[GC_BACKEND_NR] =
   {
     { NULL, NULL, NULL },              /* GC_BACKEND_ANY dummy entry.  */
-    { "GnuPG", "gpg", "gpgconf-config-file" },
-    { "GPGSM", "gpgsm", "gpgconf-config-file" },
-    { "GPG Agent", "gpg-agent", "gpgconf-config-file" },
-    { "DirMngr", "dirmngr", "gpgconf-config-file" },
+    { "GnuPG", "gpg", "gpgconf-gpg.conf" },
+    { "GPGSM", "gpgsm", "gpgconf-gpgsm.conf" },
+    { "GPG Agent", "gpg-agent", "gpgconf-gpg-agent.conf" },
+    { "DirMngr", "dirmngr", "gpgconf-dirmngr.conf" },
     { "DirMngr LDAP Server List", NULL, "ldapserverlist-file", "LDAP Server" },
   };
 
@@ -341,6 +341,10 @@ struct gc_option
      of the list so that they can be omitted from the option
      declarations.  */
 
+  /* This is true if the option is supported by this version of the
+     backend.  */
+  int active;
+
   /* The default value for this option.  This is NULL if the option is
      not present in the backend, the empty string if no default is
      available, and otherwise a quoted string.  */
@@ -369,13 +373,13 @@ static gc_option_t gc_options_gpg_agent[] =
 static gc_option_t gc_options_dirmngr[] =
  {
    /* The configuration file to which we write the changes.  */
-   { "gpgconf-config-file", GC_OPT_FLAG_NONE, GC_LEVEL_INTERNAL,
+   { "gpgconf-dirmngr.conf", GC_OPT_FLAG_NONE, GC_LEVEL_INTERNAL,
      NULL, NULL, GC_ARG_TYPE_PATHNAME, GC_BACKEND_DIRMNGR },
 
    { "Monitor",
      GC_OPT_FLAG_GROUP, GC_LEVEL_BASIC,
      NULL, "Options controlling the diagnostic output" },
-   { "verbose", GC_OPT_FLAG_NONE, GC_LEVEL_BASIC,
+   { "verbose", GC_OPT_FLAG_LIST, GC_LEVEL_BASIC,
      "dirmngr", "verbose",
      GC_ARG_TYPE_NONE, GC_BACKEND_DIRMNGR },
    { "quiet", GC_OPT_FLAG_NONE, GC_LEVEL_BASIC,
@@ -616,7 +620,7 @@ gc_component_list_options (int component, FILE *out)
       char *arg_name = NULL;
 
       /* Do not output unknown or internal options.  */
-      if (!option->default_value || option->level == GC_LEVEL_INTERNAL)
+      if (!option->active || option->level == GC_LEVEL_INTERNAL)
        {
          option++;
          continue;
@@ -740,26 +744,29 @@ find_option (gc_component_t component, const char *name,
 static char *
 get_config_pathname (gc_component_t component, gc_backend_t backend)
 {
-  char *pathname;
+  char *pathname = NULL;
   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->flags & GC_OPT_FLAG_LIST));
 
-  if (!option->default_value)
-    gc_error (1, 0, "option %s, needed by backend %s, was not initialized",
+  if (!option->active || !option->default_value)
+    gc_error (1, 0, "Option %s, needed by backend %s, was not initialized",
              gc_backend[backend].option_config_filename,
              gc_backend[backend].name);
-  if (*option->value)
+
+  if (option->value && *option->value)
     pathname = option->value;
   else
     pathname = option->default_value;
 
-  if (*pathname != '/')
-    gc_error (1, 0, "option %s, needed by backend %s, is not absolute",
+  if (pathname[1] != '/')
+    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 &pathname[1];
 }
 
 \f
@@ -772,20 +779,18 @@ retrieve_options_from_program (gc_component_t component, gc_backend_t backend)
   char *line = NULL;
   size_t line_len = 0;
   ssize_t length;
-  FILE *output;
+  FILE *config;
+  char *config_pathname;
 
-  asprintf (&cmd_line, "%s --gpgconf-list", gc_backend[backend].program);
-  if (!cmd_line)
-    gc_error (1, errno, "can not construct command line");
+  cmd_line = xasprintf ("%s --gpgconf-list", gc_backend[backend].program);
 
-  output = popen (cmd_line, "r");
-  if (!output)
+  config = popen (cmd_line, "r");
+  if (!config)
     gc_error (1, errno, "could not gather active options from %s", cmd_line);
 
-  while ((length = getline (&line, &line_len, output)) > 0)
+  while ((length = getline (&line, &line_len, config)) > 0)
     {
       gc_option_t *option;
-      char *default_value;
       char *value;
 
       /* Strip newline and carriage return, if present.  */
@@ -793,29 +798,19 @@ retrieve_options_from_program (gc_component_t component, gc_backend_t backend)
             && (line[length - 1] == '\n' || line[length - 1] == '\r'))
        line[--length] = '\0';
 
-      /* Extract default value and value, if present.  Default to
-        empty if not.  */
-      default_value = strchr (line, ':');
-      if (!default_value)
-       {
-         default_value = "";
-         value = "";
-       }
+      /* Extract default value, if present.  Default to empty if
+        not.  */
+      value = strchr (line, ':');
+      if (!value)
+       value = "";
       else
        {
-         *(default_value++) = '\0';
-         value = strchr (default_value, ':');
-         if (!value)
-           value = "";
-         else
-           {
-             char *end;
+         char *end;
 
-             *(value++) = '\0';
-             end = strchr (value, ':');
-             if (end)
-               *end = '\0';
-           }
+         *(value++) = '\0';
+         end = strchr (value, ':');
+         if (end)
+           *end = '\0';
        }
 
       /* Look up the option in the component and install the
@@ -823,20 +818,122 @@ retrieve_options_from_program (gc_component_t component, gc_backend_t backend)
       option = find_option (component, line, backend);
       if (option)
        {
-         if (option->default_value)
+         if (option->active)
            gc_error (1, errno, "option %s returned twice from %s",
                      line, cmd_line);
-         option->default_value = strdup (default_value);
-         option->value = strdup (value);
-         if (!option->default_value || !option->value)
-           gc_error (1, errno, "could not store options");
+         option->active = 1;
+         if (*value)
+           option->default_value = xstrdup (value);
        }
     }
-  if (ferror (output))
+  if (ferror (config))
     gc_error (1, errno, "error reading from %s", cmd_line);
-  if (fclose (output) && ferror (output))
+  if (fclose (config) && ferror (config))
     gc_error (1, errno, "error closing %s", cmd_line);
-  free (cmd_line);
+  xfree (cmd_line);
+
+  /* At this point, we can parse the configuration file.  */
+  config_pathname = get_config_pathname (component, backend);
+
+  config = fopen (config_pathname, "r");
+  if (!config)
+    gc_error (0, errno, "warning: can not open config file %s",
+             config_pathname);
+  else
+    {
+      while ((length = getline (&line, &line_len, config)) > 0)
+       {
+         char *name;
+         char *value;
+         gc_option_t *option;
+         
+         name = line;
+         while (*name == ' ' || *name == '\t')
+           name++;
+         if (!*name || *name == '#' || *name == '\r' || *name == '\n')
+           continue;
+
+         value = name;
+         while (*value && *value != ' ' && *value != '\t'
+                && *value != '#' && *value != '\r' && *value != '\n')
+           value++;
+         if (*value == ' ' || *value == '\t')
+           {
+             char *end;
+
+             *(value++) = '\0';
+             while (*value == ' ' || *value == '\t')
+               value++;
+
+             end = value;
+             while (*end && *end != '#' && *end != '\r' && *end != '\n')
+               end++;
+             while (end > value && (end[-1] == ' ' || end[-1] == '\t'))
+               end--;
+             *end = '\0';
+           }
+         else
+           *value = '\0';
+
+         /* Look up the option in the component and install the
+            configuration data.  */
+         option = find_option (component, line, backend);
+         if (option)
+           {
+             char *opt_value;
+
+             if (gc_arg_type[option->arg_type].fallback == GC_ARG_TYPE_NONE)
+               {
+                 if (*value)
+                   gc_error (0, 0,
+                             "warning: ignoring argument %s for option %s",
+                             value, name);
+                 opt_value = xstrdup ("Y");
+               }
+             else if (gc_arg_type[option->arg_type].fallback
+                      == GC_ARG_TYPE_STRING)
+               opt_value = xasprintf ("\"%s", percent_escape (value));
+             else
+               {
+                 /* FIXME: Verify that the number is sane.  */
+                 opt_value = xstrdup (value);
+               }
+
+             /* Now enter the option into the table.  */
+             if (!(option->flags & GC_OPT_FLAG_LIST))
+               {
+                 if (option->value)
+                   free (option->value);
+                 option->value = opt_value;
+               }
+             else
+               {
+                 if (!option->value)
+                   option->value = opt_value;
+                 else
+                   {
+                     char *opt_val = opt_value;
+
+                     if (gc_arg_type[option->arg_type].fallback
+                         == GC_ARG_TYPE_STRING)
+                       opt_val++;
+
+                     option->value = xasprintf ("%s,%s", option->value,
+                                                opt_val);
+                     xfree (opt_value);
+                   }
+               }
+           }
+       }
+
+      if (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 (line)
+    free (line);
 }
 
 
@@ -851,59 +948,62 @@ retrieve_options_from_file (gc_component_t component, gc_backend_t backend)
   char *line = NULL;
   size_t line_len = 0;
   ssize_t length;
-  char *list;
+  char *list = NULL;
 
   list_option = find_option (component,
                             gc_backend[backend].option_name, GC_BACKEND_ANY);
   assert (list_option);
+  assert (!list_option->active);
 
   list_pathname = get_config_pathname (component, backend);
-
   list_file = fopen (list_pathname, "r");
-  if (ferror (list_file))
-    gc_error (1, errno, "can not open list file %s", list_pathname);
-
-  list = strdup ("\"");
-  if (!list)
-    gc_error (1, errno, "can not allocate initial list string");
-
-  while ((length = getline (&line, &line_len, list_file)) > 0)
+  if (!list_file)
+    gc_error (0, errno, "warning: can not open list file %s", list_pathname);
+  else
     {
-      char *start;
-      char *end;
-      char *new_list;
-
-      start = line;
-      while (*start == ' ' || *start == '\t')
-       start++;
-      if (!*start || *start == '#' || *start == '\r' || *start == '\n')
-       continue;
-
-      end = start;
-      while (*end && *end != '#' && *end != '\r' && *end != '\n')
-       end++;
-      /* Walk back to skip trailing white spaces.  Looks evil, but
-        works because of the conditions on START and END imposed
-        at this point (END is at least START + 1, and START is
-        not a whitespace character).  */
-      while (*(end - 1) == ' ' || *(end - 1) == '\t')
-       end--;
-      *end = '\0';
-      /* FIXME: Oh, no!  This is so lame!  Use realloc and really
-        append.  */
-      if (list)
+
+      while ((length = getline (&line, &line_len, list_file)) > 0)
        {
-         asprintf (&new_list, "%s,%s", list, percent_escape (start));
-         free (list);
-         list = new_list;
+         char *start;
+         char *end;
+         char *new_list;
+
+         start = line;
+         while (*start == ' ' || *start == '\t')
+           start++;
+         if (!*start || *start == '#' || *start == '\r' || *start == '\n')
+           continue;
+
+         end = start;
+         while (*end && *end != '#' && *end != '\r' && *end != '\n')
+           end++;
+         /* Walk back to skip trailing white spaces.  Looks evil, but
+            works because of the conditions on START and END imposed
+            at this point (END is at least START + 1, and START is
+            not a whitespace character).  */
+         while (*(end - 1) == ' ' || *(end - 1) == '\t')
+           end--;
+         *end = '\0';
+         /* FIXME: Oh, no!  This is so lame!  Use realloc and really
+            append.  */
+         if (list)
+           {
+             new_list = xasprintf ("%s,%s", list, percent_escape (start));
+             xfree (list);
+             list = new_list;
+           }
+         else
+           list = xasprintf ("\"%s", percent_escape (start));
        }
-      if (!list)
-       gc_error (1, errno, "can not construct list");
+      if (ferror (list_file))
+       gc_error (1, errno, "can not read list file %s", list_pathname);
     }
-  if (ferror (list_file))
-    gc_error (1, errno, "can not read list file %s", list_pathname);
-  list_option->default_value = "";
+
+  list_option->active = 1;
   list_option->value = list;
+
+  if (line)
+    free (line);
 }
 
 
@@ -983,7 +1083,7 @@ change_options_program (gc_component_t component, gc_backend_t backend,
   /* True if we are within the marker in the config file.  */
   int in_marker = 0;
   gc_option_t *option;
-  char *line;
+  char *line = NULL;
   size_t line_len;
   ssize_t length;
   int res;
@@ -995,22 +1095,16 @@ change_options_program (gc_component_t component, gc_backend_t backend,
   char *orig_filename;
 
   /* FIXME.  Throughout the function, do better error reporting.  */
-  dest_filename = strdup (get_config_pathname (component, backend));
-  if (!dest_filename)
-    return -1;
-  asprintf (&src_filename, "%s.gpgconf.%i.new", dest_filename, getpid ());
-  if (!src_filename)
-    return -1;
-  asprintf (&orig_filename, "%s.gpgconf.%i.bak", dest_filename, getpid ());
-  if (!orig_filename)
-    return -1;
+  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 ());
 
   res = link (dest_filename, orig_filename);
   if (res < 0 && errno != ENOENT)
     return -1;
   if (res < 0)
     {
-      free (orig_filename);
+      xfree (orig_filename);
       orig_filename = NULL;
     }
   /* We now initialize the return strings, so the caller can do the
@@ -1163,6 +1257,8 @@ change_options_program (gc_component_t component, gc_backend_t backend,
       if (ferror (dest_file))
        goto change_one_err;
     }
+  if (line)
+    free (line);
   res = fclose (src_file);
   if (res)
     {
@@ -1183,6 +1279,8 @@ change_options_program (gc_component_t component, gc_backend_t backend,
   return 0;
 
  change_one_err:
+  if (line)
+    free (line);
   res = errno;
   if (src_file)
     {
@@ -1243,7 +1341,7 @@ gc_component_change_options (int component, FILE *in)
        gc_error (1, 0, "unknown option %s", line);
 
       option_check_validity (option, value);
-      option->new_value = strdup (value);
+      option->new_value = xstrdup (value);
     }
 
   /* Now that we have collected and locally verified the changes,
@@ -1335,4 +1433,6 @@ gc_component_change_options (int component, FILE *in)
        }
       gc_error (1, saved_errno, "could not commit changes");
     }
+  if (line)
+    free (line);
 }