gpgconf: New command --show-configs.

* tools/gpgconf.c (aShowConfigs): New.
(opts): Add --show-configs.
(CUTLINE_FMT): New.
(show_version_gnupg): Add arg "prefix" and adjust caller.
(my_copy_file): New.
(show_configs_one_file): New.New.
(show_configs): New.
(main): Call show_configs.
--

The ability to have a consolidated list of all config files is very
useful for support cases.  This is in particular important due to the
global config files and their conditional constructs.

Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
Werner Koch 2021-11-04 16:34:26 +01:00
parent 6507c6ab10
commit 8fe3f57643
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
1 changed files with 155 additions and 6 deletions

View File

@ -68,6 +68,7 @@ enum cmd_and_opt_values
aRemoveSocketDir,
aApplyProfile,
aReload,
aShowConfigs,
aShowVersions
};
@ -100,7 +101,7 @@ static ARGPARSE_OPTS opts[] =
{ aCreateSocketDir, "create-socketdir", 256, "@"},
{ aRemoveSocketDir, "remove-socketdir", 256, "@"},
ARGPARSE_c (aShowVersions, "show-versions", "@"),
ARGPARSE_c (aShowConfigs, "show-configs", "@"),
{ 301, NULL, 0, N_("@\nOptions:\n ") },
@ -121,11 +122,17 @@ static ARGPARSE_OPTS opts[] =
};
#define CUTLINE_FMT \
"--8<---------------cut here---------------%s------------->8---\n"
/* The stream to output the status information. Status Output is disabled if
* this is NULL. */
static estream_t statusfp;
static void show_versions (estream_t fp);
static void show_configs (estream_t fp);
@ -637,6 +644,7 @@ main (int argc, char **argv)
case aCreateSocketDir:
case aRemoveSocketDir:
case aShowVersions:
case aShowConfigs:
cmd = pargs.r_opt;
break;
@ -952,6 +960,13 @@ main (int argc, char **argv)
}
break;
case aShowConfigs:
{
get_outfp (&outfp);
show_configs (outfp);
}
break;
}
if (outfp != es_stdout)
@ -1008,16 +1023,17 @@ get_revision_from_blurb (const char *blurb, int *r_len)
static void
show_version_gnupg (estream_t fp)
show_version_gnupg (estream_t fp, const char *prefix)
{
es_fprintf (fp, "* GnuPG %s (%s)\n%s\n",
strusage (13), BUILD_REVISION, strusage (17));
es_fprintf (fp, "%s%sGnuPG %s (%s)\n%s%s\n", prefix, *prefix?"":"* ",
strusage (13), BUILD_REVISION, prefix, gpgrt_strusage (17));
#ifdef HAVE_W32_SYSTEM
{
OSVERSIONINFO osvi = { sizeof (osvi) };
GetVersionEx (&osvi);
es_fprintf (fp, "Windows %lu.%lu build %lu%s%s%s\n",
es_fprintf (fp, "%sWindows %lu.%lu build %lu%s%s%s\n",
prefix,
(unsigned long)osvi.dwMajorVersion,
(unsigned long)osvi.dwMinorVersion,
(unsigned long)osvi.dwBuildNumber,
@ -1122,7 +1138,7 @@ show_versions_via_dirmngr (estream_t fp)
static void
show_versions (estream_t fp)
{
show_version_gnupg (fp);
show_version_gnupg (fp, "");
es_fputc ('\n', fp);
show_version_libgcrypt (fp);
es_fputc ('\n', fp);
@ -1130,3 +1146,136 @@ show_versions (estream_t fp)
es_fputc ('\n', fp);
show_versions_via_dirmngr (fp);
}
/* Copy data from file SRC to DST. Returns 0 on success or an error
* code on failure. */
static gpg_error_t
my_copy_file (estream_t src, estream_t dst)
{
#define BUF_LEN 4096
char buffer[BUF_LEN];
int len;
int written;
do
{
len = gpgrt_fread (buffer, 1, BUF_LEN, src);
if (!len)
break;
written = gpgrt_fwrite (buffer, 1, len, dst);
if (written != len)
break;
}
while (!gpgrt_feof (src) && !gpgrt_ferror (src) && !gpgrt_ferror (dst));
if (gpgrt_ferror (src) || gpgrt_ferror (dst) || !gpgrt_feof (src))
return gpg_error_from_syserror ();
if (gpgrt_fflush (dst))
return gpg_error_from_syserror ();
return 0;
}
/* Helper for show_configs */
static void
show_configs_one_file (const char *fname, int global, estream_t outfp)
{
gpg_error_t err;
estream_t fp;
fp = es_fopen (fname, "r");
if (!fp)
{
err = gpg_error_from_syserror ();
es_fprintf (outfp, "###\n### %s config \"%s\": %s\n###\n",
global? "global":"local", fname,
(gpg_err_code (err) == GPG_ERR_ENOENT)?
"not installed" : gpg_strerror (err));
}
else
{
es_fprintf (outfp, "###\n### %s config \"%s\"\n###\n",
global? "global":"local", fname);
es_fprintf (outfp, CUTLINE_FMT, "start");
err = my_copy_file (fp, outfp);
if (err)
log_error ("error copying file \"%s\": %s\n",
fname, gpg_strerror (err));
es_fprintf (outfp, CUTLINE_FMT, "end--");
es_fclose (fp);
}
}
/* Show all config files. */
static void
show_configs (estream_t outfp)
{
static const char *names[] = { "common.conf", "gpg-agent.conf",
"scdaemon.conf", "dirmngr.conf",
"gpg.conf", "gpgsm.conf" };
gpg_error_t err;
int idx;
char *fname;
gnupg_dir_t dir;
gnupg_dirent_t dir_entry;
size_t n;
int any;
es_fprintf (outfp, "### Dump of all standard config files\n");
show_version_gnupg (outfp, "### ");
es_fprintf (outfp, "### Libgcrypt %s\n", gcry_check_version (NULL));
es_fprintf (outfp, "### GpgRT %s\n", gpg_error_check_version (NULL));
es_fprintf (outfp, "###\n\n");
for (idx = 0; idx < DIM (names); idx++)
{
fname = make_filename (gnupg_sysconfdir (), names[idx], NULL);
show_configs_one_file (fname, 1, outfp);
xfree (fname);
fname = make_filename (gnupg_homedir (), names[idx], NULL);
show_configs_one_file (fname, 0, outfp);
xfree (fname);
es_fprintf (outfp, "\n");
}
/* Check for uncommon files in the home directory. */
dir = gnupg_opendir (gnupg_homedir ());
if (!dir)
{
err = gpg_error_from_syserror ();
log_error ("error reading directory \"%s\": %s\n",
gnupg_homedir (), gpg_strerror (err));
return;
}
any = 0;
while ((dir_entry = gnupg_readdir (dir)))
{
for (idx = 0; idx < DIM (names); idx++)
{
n = strlen (names[idx]);
if (!ascii_strncasecmp (dir_entry->d_name, names[idx], n)
&& dir_entry->d_name[n] == '-'
&& ascii_strncasecmp (dir_entry->d_name, "gpg.conf-1", 10))
{
if (!any)
{
any = 1;
es_fprintf (outfp,
"###\n"
"### Warning: suspicious files in \"%s\":\n",
gnupg_homedir ());
}
es_fprintf (outfp, "### %s\n", dir_entry->d_name);
}
}
}
if (any)
es_fprintf (outfp, "###\n");
gnupg_closedir (dir);
}