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.
This commit is contained in:
Marcus Brinkmann 2008-05-19 22:46:41 +00:00
parent 102b285a2d
commit 7d714a3788
6 changed files with 195 additions and 110 deletions

View 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> 2008-05-15 Marcus Brinkmann <marcus@g10code.de>
* gpg.texi (Operational GPG Commands): Mention the way to change * gpg.texi (Operational GPG Commands): Mention the way to change

View File

@ -230,6 +230,9 @@ List all options of the component @var{component}.
@item --change-options @var{component} @item --change-options @var{component}
Change the options of the component @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 @item --apply-defaults
Update all configuration files with values taken from the global Update all configuration files with values taken from the global
configuration file (usually @file{/etc/gnupg/gpgconf.conf}). 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 Outputs additional information while running. Specifically, this
extends numerical field values by human-readable descriptions. extends numerical field values by human-readable descriptions.
@c FIXME: Not yet supported. @item -n
@c @item -n @itemx --dry-run
@c @itemx --dry-run Do not actually change anything. This is currently only implemented
@c Do not actually change anything. Useful together with for @code{--change-options} and can be used for testing purposes.
@c @code{--change-options} for testing purposes.
@item -r @item -r
@itemx --runtime @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: dirmngr:Directory Manager:/usr/local/bin/dirmngr:0:0:
@end example @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 @node Listing options
@subsection 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. option). Otherwise, the option will be set to the specified value.
@end table @end table
@noindent
The output of the command is the same as that of
@code{--check-options} for the modified configuration file.
Examples: Examples:
To set the force option, which is of basic type @code{none (0)}: To set the force option, which is of basic type @code{none (0)}:

View 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> 2008-05-09 Werner Koch <wk@g10code.com>
* gpgconf-comp.c (my_dgettext) [USE_SIMPLE_GETTEXT]: Hack to * gpgconf-comp.c (my_dgettext) [USE_SIMPLE_GETTEXT]: Hack to

View File

@ -1317,118 +1317,140 @@ collect_error_output (int fd, const char *tag)
} }
/* Check the options of a single component. Returns 0 if everything
/* Check all components that are available. */ is OK. */
void int
gc_component_check_programs (FILE *out) 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; unsigned int result;
int backend_seen[GC_BACKEND_NR]; int backend_seen[GC_BACKEND_NR];
gc_backend_t backend; gc_backend_t backend;
gc_option_t *option; 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; pid_t pid;
int exitcode; int exitcode;
int filedes[2]; 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 /* 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 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 fucntion to create a portable pipe outside of exechelp. Thus it
is easier to use the tempfile approach. */ 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) if ((option->flags & GC_OPT_FLAG_GROUP))
continue; 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;
for (backend = 0; backend < GC_BACKEND_NR; backend++) break;
backend_seen[backend] = 0; }
if (! option || ! option->name)
return 0;
option = gc_component[component].options; pgmname = gnupg_module_name (gc_backend[backend].module_name);
for (; option && option->name; option++) i = 0;
{ if (conf_file)
if ((option->flags & GC_OPT_FLAG_GROUP)) {
continue; argv[i++] = "--options";
backend = option->backend; argv[i++] = conf_file;
if (backend_seen[backend]) }
continue; argv[i++] = "--gpgconf-test";
backend_seen[backend] = 1; argv[i++] = NULL;
assert (backend != GC_BACKEND_ANY);
if (!gc_backend[backend].program) err = gnupg_create_inbound_pipe (filedes);
continue; if (err)
if (!gc_backend[backend].module_name) gc_error (1, 0, _("error creating a pipe: %s\n"),
continue; 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;
pgmname = gnupg_module_name (gc_backend[backend].module_name); desc = gc_component[component].desc;
argv[0] = "--gpgconf-test"; desc = my_dgettext (gc_component[component].desc_domain, desc);
argv[1] = NULL; 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);
}
err = gnupg_create_inbound_pipe (filedes); while (errlines)
if (err) {
gc_error (1, 0, _("error creating a pipe: %s\n"), error_line_t tmp = errlines->next;
gpg_strerror (err)); xfree (errlines);
errlines = tmp;
}
result = 0; return result;
errlines = NULL; }
if (gnupg_spawn_process_fd (pgmname, argv, -1, -1, filedes[1], &pid))
{
close (filedes[0]); /* Check all components that are available. */
close (filedes[1]); void
result |= 1; /* Program could not be run. */ gc_check_programs (FILE *out)
} {
else gc_component_t component;
{
close (filedes[1]); for (component = 0; component < GC_COMPONENT_NR; component++)
errlines = collect_error_output (filedes[0], gc_component_check_options (component, out, NULL);
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 */
}
}
} }
@ -2831,7 +2853,7 @@ change_one_value (gc_option_t *option, int *runtime,
modifications are expected to already have been set to the global modifications are expected to already have been set to the global
table. */ table. */
void void
gc_component_change_options (int component, FILE *in) gc_component_change_options (int component, FILE *in, FILE *out)
{ {
int err = 0; int err = 0;
int runtime[GC_BACKEND_NR]; 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], err = change_options_program (component, option->backend,
&dest_pathname[option->backend], &src_pathname[option->backend],
&orig_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 else
err = change_options_file (component, option->backend, err = change_options_file (component, option->backend,
&src_pathname[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 i;
int saved_errno = errno; int saved_errno = errno;
/* An error occured. */ /* An error occured 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_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;

View File

@ -43,6 +43,7 @@ enum cmd_and_opt_values
aCheckPrograms, aCheckPrograms,
aListOptions, aListOptions,
aChangeOptions, aChangeOptions,
aCheckOptions,
aApplyDefaults, aApplyDefaults,
aListConfig, aListConfig,
aCheckConfig aCheckConfig
@ -59,6 +60,7 @@ static ARGPARSE_OPTS opts[] =
{ aCheckPrograms, "check-programs", 256, N_("check all programs") }, { aCheckPrograms, "check-programs", 256, N_("check all programs") },
{ aListOptions, "list-options", 256, N_("|COMPONENT|list options") }, { aListOptions, "list-options", 256, N_("|COMPONENT|list options") },
{ aChangeOptions, "change-options", 256, N_("|COMPONENT|change options") }, { aChangeOptions, "change-options", 256, N_("|COMPONENT|change options") },
{ aCheckOptions, "check-options", 256, N_("|COMPONENT|check options") },
{ aApplyDefaults, "apply-defaults", 256, { aApplyDefaults, "apply-defaults", 256,
N_("apply global default values") }, N_("apply global default values") },
{ aListConfig, "list-config", 256, { aListConfig, "list-config", 256,
@ -167,6 +169,7 @@ main (int argc, char **argv)
case aCheckPrograms: case aCheckPrograms:
case aListOptions: case aListOptions:
case aChangeOptions: case aChangeOptions:
case aCheckOptions:
case aApplyDefaults: case aApplyDefaults:
case aListConfig: case aListConfig:
case aCheckConfig: case aCheckConfig:
@ -192,11 +195,12 @@ main (int argc, char **argv)
case aCheckPrograms: case aCheckPrograms:
/* Check all programs. */ /* Check all programs. */
gc_component_check_programs (get_outfp (&outfp)); gc_check_programs (get_outfp (&outfp));
break; break;
case aListOptions: case aListOptions:
case aChangeOptions: case aChangeOptions:
case aCheckOptions:
if (!fname) if (!fname)
{ {
fputs (_("usage: gpgconf [options] "), stderr); fputs (_("usage: gpgconf [options] "), stderr);
@ -219,8 +223,10 @@ main (int argc, char **argv)
exit (1); exit (1);
if (cmd == aListOptions) if (cmd == aListOptions)
gc_component_list_options (idx, get_outfp (&outfp)); 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;

View File

@ -43,7 +43,7 @@ void gc_error (int status, int errnum, const char *fmt, ...);
void gc_component_list_components (FILE *out); void gc_component_list_components (FILE *out);
/* List all programs along with their status. */ /* 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 /* Find the component with the name NAME. Returns -1 if not
found. */ found. */
@ -57,7 +57,12 @@ void gc_component_retrieve_options (int component);
void gc_component_list_options (int component, FILE *out); void gc_component_list_options (int component, FILE *out);
/* Read the modifications from IN and apply them. */ /* 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. */ /* Process global configuration file. */
int gc_process_gpgconf_conf (const char *fname, int update, int defaults, int gc_process_gpgconf_conf (const char *fname, int update, int defaults,