1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-12-22 10:19:57 +01:00

tools: Let watchgnupg determine the socket name via gpgconf.

* tools/watchgnupg.c: Include sys/wait.h.
(GNUPG_DEF_COPYRIGHT_LINE): Add a default value for standalone
building.
(get_logname): New.
(main): Use a default socket name and add option --homedir.
--

This is quite convenient and saves a lot of typing or shell alias
definitions.

Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
Werner Koch 2020-01-20 16:50:56 +01:00
parent 7f12fb55f9
commit e0d9181ad1
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
2 changed files with 159 additions and 26 deletions

View File

@ -50,19 +50,30 @@ listener for such a socket. It ameliorates the output with a time stamp
and makes sure that long lines are not interspersed with log output from and makes sure that long lines are not interspersed with log output from
other utilities. This tool is not available for Windows. other utilities. This tool is not available for Windows.
@noindent @noindent
@command{watchgnupg} is commonly invoked as @command{watchgnupg} is commonly invoked as
@example
watchgnupg
@end example
which is a shorthand for
@example @example
watchgnupg --force $(gpgconf --list-dirs socketdir)/S.log watchgnupg --force $(gpgconf --list-dirs socketdir)/S.log
@end example @end example
To watch GnuPG running with a different home directory, use
@example
watchgnupg --homedir DIR
@end example
@manpause @manpause
@noindent @noindent
This starts it on the current terminal for listening on the standard This starts it on the current terminal for listening on the standard
logging socket (which is either @file{~/.gnupg/S.log} or logging socket (this is commonly @file{/var/run/user/UID/gnupg/S.log}
@file{/var/run/user/UID/gnupg/S.log}). or if no such user directory hierarchy exists @file{~/.gnupg/S.log}).
@mansect options @mansect options
@noindent @noindent
@ -72,12 +83,20 @@ logging socket (which is either @file{~/.gnupg/S.log} or
@item --force @item --force
@opindex force @opindex force
Delete an already existing socket file. Delete an already existing socket file. This option is implictly used
if no socket name has been given on the command line.
@item --homedir @var{DIR}
If no socket name is given on the command line, pass @var{DIR} to
gpgconf so that the socket for a GnuPG running with DIR has its home
directory is used. Note that the environment variable @var{GNUPGHOME}
is ignored by watchgnupg.
@anchor{option watchgnupg --tcp} @anchor{option watchgnupg --tcp}
@item --tcp @var{n} @item --tcp @var{n}
Instead of reading from a local socket, listen for connects on TCP port Instead of reading from a local socket, listen for connects on TCP
@var{n}. port @var{n}. A Unix domain socket can optionally also be given as a
second source. This option does not use a default socket name.
@item --time-only @item --time-only
@opindex time-only @opindex time-only
@ -102,14 +121,14 @@ Display a brief help page and exit.
@chapheading Examples @chapheading Examples
@example @example
$ watchgnupg --force --time-only $(gpgconf --list-dirs socketdir)/S.log $ watchgnupg --time-only
@end example @end example
This waits for connections on the local socket This waits for connections on the local socket
(e.g. @file{/home/foo/.gnupg/S.log}) and shows all log entries. To (e.g. @file{/var/run/user/1234/gnupg/S.log}) and shows all log
make this work the option @option{log-file} needs to be used with all entries. To make this work the option @option{log-file} needs to be
modules which logs are to be shown. The suggested entry for the used with all modules which logs are to be shown. The suggested entry
configuration files is: for the configuration files is:
@example @example
log-file socket:// log-file socket://

View File

@ -1,5 +1,6 @@
/* watchgnupg.c - Socket server for GnuPG logs /* watchgnupg.c - Socket server for GnuPG logs
* Copyright (C) 2003, 2004, 2010 Free Software Foundation, Inc. * Copyright (C) 2003, 2004, 2010 Free Software Foundation, Inc.
* Copyright (C) 2003, 2004, 2010, 2020 g10 Code GmbH
* *
* This file is part of GnuPG. * This file is part of GnuPG.
* *
@ -30,6 +31,8 @@
#include <unistd.h> #include <unistd.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/un.h> #include <sys/un.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <fcntl.h> #include <fcntl.h>
@ -53,6 +56,10 @@
#include "../common/mischelp.h" #include "../common/mischelp.h"
#endif #endif
#ifndef GNUPG_DEF_COPYRIGHT_LINE
#define GNUPG_DEF_COPYRIGHT_LINE "Copyright (C) 2020 g10 Code GmbH"
#endif
static int verbose; static int verbose;
static int time_only; static int time_only;
@ -248,6 +255,86 @@ setup_client (int server_fd, int is_un)
} }
/* Get the logsocketname by reading from gpgconf. Caller needs to
* release the buffer. */
static char *
get_logname (const char *homedir)
{
int rp[2];
pid_t pid;
int i, c;
unsigned int pos;
char filename[1024], *buf;
FILE *fp;
if (pipe (rp) == -1)
die ("error creating a pipe: %s", strerror (errno));
pid = fork ();
if (pid == -1)
die ("error forking process: %s", strerror (errno));
if (!pid)
{ /* Child. */
int fd;
fd = open ("/dev/null", O_WRONLY);
if (fd == -1)
die ("can't open '/dev/null': %s", strerror (errno));
if (fd != 0 && dup2 (fd, 0) == -1)
die ("dup2 stderr failed: %s", strerror (errno));
/* Connect stdout to our pipe. */
if (rp[1] != 1 && dup2 (rp[1], 1) == -1)
die ("dup2 stdout failed: %s", strerror (errno));
/* Close other files. 20 is an arbitrary number; at this point
* we have not opened many files. */
for (i=3; i < 20; i++)
close (i);
errno = 0;
if (homedir)
execlp ("gpgconf", "gpgconf", "--homedir", homedir,
"-0", "--list-dirs", "socketdir", NULL);
else
execlp ("gpgconf", "gpgconf",
"-0", "--list-dirs", "socketdir", NULL);
die ("failed to exec gpgconf: %s", strerror (errno));
}
/* Parent. */
close (rp[1]);
fp = fdopen (rp[0], "r");
if (!fp)
die ("can't fdopen pipe for reading: %s", strerror (errno));
pos = 0;
while ((c=getc (fp)) != EOF)
{
if (pos+1 >= sizeof filename)
die ("gpgconf returned a too long filename\n");
filename[pos++] = c;
if (!c)
break;
}
fclose (fp);
if (c == EOF)
die ("error reading from gpgconf: %s", "premature EOF");
while ((i=waitpid (pid, NULL, 0)) == -1 && errno == EINTR)
;
if (i == -1)
die ("waiting for gpgconf failed: %s", strerror (errno));
buf = xmalloc (strlen (filename) + 6 + 1);
strcpy (buf, filename);
strcat (buf, "/S.log");
return buf;
}
static void static void
print_version (int with_help) print_version (int with_help)
@ -262,17 +349,19 @@ print_version (int with_help)
if (with_help) if (with_help)
fputs fputs
("\n" ("\n"
"Usage: " PGM " [OPTIONS] SOCKETNAME\n" "Usage: " PGM " [OPTIONS] [SOCKETNAME]\n"
" " PGM " [OPTIONS] PORT [SOCKETNAME]\n" " " PGM " [OPTIONS] PORT [SOCKETNAME]\n"
"Open the local socket SOCKETNAME (or the TCP port PORT)\n" "Open the local socket SOCKETNAME (or the TCP port PORT)\n"
"and display log messages\n" "and display log messages. If --tcp is not used and no\n"
"socket name is given, it is taken from the gpgconf tool.\n"
"\n" "\n"
" --tcp listen on a TCP port and optionally on a local socket\n" " --tcp listen on a TCP port and optionally on a local socket\n"
" --force delete an already existing socket file\n" " --force delete an already existing socket file\n"
" --verbose enable extra informational output\n" " --verbose enable extra informational output\n"
" --time-only print only the time; not a full timestamp\n" " --time-only print only the time; not a full timestamp\n"
" --version print version of the program and exit\n" " --homedir DIR use DIR for gpgconf's --homedir option\n"
" --help display this help and exit\n" " --version print version of the program and exit\n"
" --help display this help and exit\n"
BUGREPORT_LINE, stdout ); BUGREPORT_LINE, stdout );
exit (0); exit (0);
@ -284,6 +373,8 @@ main (int argc, char **argv)
int last_argc = -1; int last_argc = -1;
int force = 0; int force = 0;
int tcp = 0; int tcp = 0;
char *homedir = NULL;
char *logname = NULL;
struct sockaddr_un srvr_addr_un; struct sockaddr_un srvr_addr_un;
struct sockaddr_in srvr_addr_in; struct sockaddr_in srvr_addr_in;
@ -330,11 +421,31 @@ main (int argc, char **argv)
tcp = 1; tcp = 1;
argc--; argv++; argc--; argv++;
} }
else if (!strcmp (*argv, "--homedir"))
{
argc--; argv++;
if (!argc)
die ("option --homedir requires an argument\n");
argc--;
homedir = *argv++;
}
} }
if (!((!tcp && argc == 1) || (tcp && (argc == 1 || argc == 2)))) if (!tcp && argc == 1)
;
else if (tcp && (argc == 1 || argc == 2))
; /* Option --tcp optionally allows to also read from a socket. */
else if (!tcp && !argc)
{ {
fprintf (stderr, "usage: " PGM " socketname\n" /* No args given - figure out the socket using gpgconf. We also
* force overwriting the socket because the constructed name
* can't be some accidently given name. */
logname = get_logname (homedir);
force = 1;
}
else
{
fprintf (stderr, "usage: " PGM " [socketname]\n"
" " PGM " --tcp port [socketname]\n"); " " PGM " --tcp port [socketname]\n");
exit (1); exit (1);
} }
@ -348,6 +459,8 @@ main (int argc, char **argv)
{ {
port = 0; port = 0;
} }
if (argc)
logname = *argv;
setvbuf (stdout, NULL, _IOLBF, 0); setvbuf (stdout, NULL, _IOLBF, 0);
@ -366,13 +479,13 @@ main (int argc, char **argv)
else else
server_in = -1; server_in = -1;
if (argc) if (logname)
{ {
server_un = socket (PF_LOCAL, SOCK_STREAM, 0); server_un = socket (PF_LOCAL, SOCK_STREAM, 0);
if (server_un == -1) if (server_un == -1)
die ("socket(PF_LOCAL) failed: %s\n", strerror (errno)); die ("socket(PF_LOCAL) failed: %s\n", strerror (errno));
if (verbose) if (verbose)
fprintf (stderr, "listening on socket '%s'\n", *argv); fprintf (stderr, "listening on socket '%s'\n", logname);
} }
else else
server_un = -1; server_un = -1;
@ -406,11 +519,12 @@ main (int argc, char **argv)
addr_in = (struct sockaddr *)&srvr_addr_in; addr_in = (struct sockaddr *)&srvr_addr_in;
addrlen_in = sizeof srvr_addr_in; addrlen_in = sizeof srvr_addr_in;
} }
if (argc) if (logname)
{ {
memset (&srvr_addr_un, 0, sizeof srvr_addr_un); memset (&srvr_addr_un, 0, sizeof srvr_addr_un);
srvr_addr_un.sun_family = AF_LOCAL; srvr_addr_un.sun_family = AF_LOCAL;
strncpy (srvr_addr_un.sun_path, *argv, sizeof (srvr_addr_un.sun_path)-1); strncpy (srvr_addr_un.sun_path, logname,
sizeof (srvr_addr_un.sun_path)-1);
srvr_addr_un.sun_path[sizeof (srvr_addr_un.sun_path) - 1] = 0; srvr_addr_un.sun_path[sizeof (srvr_addr_un.sun_path) - 1] = 0;
addr_un = (struct sockaddr *)&srvr_addr_un; addr_un = (struct sockaddr *)&srvr_addr_un;
addrlen_un = SUN_LEN (&srvr_addr_un); addrlen_un = SUN_LEN (&srvr_addr_un);
@ -431,7 +545,7 @@ main (int argc, char **argv)
goto again; goto again;
} }
else else
die ("bind to '%s' failed: %s\n", *argv, strerror (errno)); die ("bind to '%s' failed: %s\n", logname, strerror (errno));
} }
if (server_in != -1 && listen (server_in, 5)) if (server_in != -1 && listen (server_in, 5))