1
/* watchgnupg.c - Socket server for GnuPG logs
2
* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
4
* This file is part of GnuPG.
6
* GnuPG is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
11
* GnuPG is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
32
#include <sys/socket.h>
37
#define PGM "watchgnupg"
39
/* Allow for a standalone build. */
41
#define MYVERSION_LINE PGM " (GnuPG) " VERSION
42
#define BUGREPORT_LINE "\nReport bugs to <bug-gnupg@gnu.org>.\n"
44
#define MYVERSION_LINE PGM
45
#define BUGREPORT_LINE ""
52
die (const char *format, ...)
57
fprintf (stderr, "%s: ", PGM);
59
va_start (arg_ptr, format);
60
vfprintf (stderr, format, arg_ptr);
69
/* err (const char *format, ...) */
71
/* va_list arg_ptr; */
73
/* fflush (stdout); */
74
/* fprintf (stderr, "%s: ", PGM); */
76
/* va_start (arg_ptr, format); */
77
/* vfprintf (stderr, format, arg_ptr); */
78
/* va_end (arg_ptr); */
79
/* putc ('\n', stderr); */
92
xcalloc (size_t n, size_t m)
94
void *p = calloc (n, m);
101
xrealloc (void *old, size_t n)
103
void *p = realloc (old, n);
111
struct client_s *next;
113
size_t size; /* Allocated size of buffer. */
114
size_t len; /* Current length of buffer. */
115
unsigned char *buffer; /* Buffer to with data already read. */
118
typedef struct client_s *client_t;
123
print_fd_and_time (int fd)
126
time_t atime = time (NULL);
128
tp = localtime (&atime);
129
printf ("%3d - %04d-%02d-%02d %02d:%02d:%02d ",
131
1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday,
132
tp->tm_hour, tp->tm_min, tp->tm_sec );
136
/* Print LINE for the client identified by C. Calling this function
137
witgh LINE set to NULL, will flush the internal buffer. */
139
print_line (client_t c, const char *line)
146
if (c->buffer && c->len)
148
print_fd_and_time (c->fd);
149
fwrite (c->buffer, c->len, 1, stdout);
156
while ((s = strchr (line, '\n')))
158
print_fd_and_time (c->fd);
159
if (c->buffer && c->len)
161
fwrite (c->buffer, c->len, 1, stdout);
164
fwrite (line, s - line + 1, 1, stdout);
170
if (c->len + n >= c->size)
172
c->size += ((n + 255) & ~255);
173
c->buffer = (c->buffer
174
? xrealloc (c->buffer, c->size)
175
: xmalloc (c->size));
177
memcpy (c->buffer + c->len, line, n);
184
print_version (int with_help)
186
fputs (MYVERSION_LINE "\n"
187
"Copyright (C) 2004 Free Software Foundation, Inc.\n"
188
"This program comes with ABSOLUTELY NO WARRANTY.\n"
189
"This is free software, and you are welcome to redistribute it\n"
190
"under certain conditions. See the file COPYING for details.\n",
195
"Usage: " PGM " [OPTIONS] SOCKETNAME\n"
196
"Open the local socket SOCKETNAME and display log messages\n"
198
" --force delete an already existing socket file\n"
199
" --verbose enable extra informational output\n"
200
" --version print version of the program and exit\n"
201
" --help display this help and exit\n"
202
BUGREPORT_LINE, stdout );
208
main (int argc, char **argv)
213
struct sockaddr_un srvr_addr;
217
client_t client_list = NULL;
223
while (argc && last_argc != argc )
226
if (!strcmp (*argv, "--"))
231
else if (!strcmp (*argv, "--version"))
233
else if (!strcmp (*argv, "--help"))
235
else if (!strcmp (*argv, "--verbose"))
240
else if (!strcmp (*argv, "--force"))
249
fprintf (stderr, "usage: " PGM " socketname\n");
255
fprintf (stderr, "opening socket `%s'\n", *argv);
257
setvbuf (stdout, NULL, _IOLBF, 0);
259
server = socket (PF_LOCAL, SOCK_STREAM, 0);
261
die ("socket() failed: %s\n", strerror (errno));
263
/* We better set the listening socket to non-blocking so that we
264
don't get bitten by race conditions in accept. The should not
265
happen for Unix Domain sockets but well, shit happens. */
266
flags = fcntl (server, F_GETFL, 0);
268
die ("fcntl (F_GETFL) failed: %s\n", strerror (errno));
269
if ( fcntl (server, F_SETFL, (flags | O_NONBLOCK)) == -1)
270
die ("fcntl (F_SETFL) failed: %s\n", strerror (errno));
273
memset (&srvr_addr, 0, sizeof srvr_addr);
274
srvr_addr.sun_family = AF_LOCAL;
275
strncpy (srvr_addr.sun_path, *argv, sizeof (srvr_addr.sun_path) - 1);
276
srvr_addr.sun_path[sizeof (srvr_addr.sun_path) - 1] = 0;
277
addrlen = (offsetof (struct sockaddr_un, sun_path)
278
+ strlen (srvr_addr.sun_path) + 1);
282
if (bind (server, (struct sockaddr *) &srvr_addr, addrlen))
284
if (errno == EADDRINUSE && force)
287
remove (srvr_addr.sun_path);
290
die ("bind to `%s' failed: %s\n", *argv, strerror (errno));
293
if (listen (server, 5))
294
die ("listen failed: %s\n", strerror (errno));
302
/* Usually we don't have that many connections, thus it is okay
303
to set them allways from scratch and don't maintain an active
306
FD_SET (server, &rfds);
308
for (client = client_list; client; client = client->next)
309
if (client->fd != -1)
311
FD_SET (client->fd, &rfds);
312
if (client->fd > max_fd)
316
if (select (max_fd + 1, &rfds, NULL, NULL, NULL) <= 0)
317
continue; /* Ignore any errors. */
319
if (FD_ISSET (server, &rfds)) /* New connection. */
321
struct sockaddr_un clnt_addr;
324
addrlen = sizeof clnt_addr;
325
fd = accept (server, (struct sockaddr *) &clnt_addr, &addrlen);
328
printf ("[accepting connection failed: %s]\n", strerror (errno));
330
else if (fd >= FD_SETSIZE)
333
printf ("[connection request denied: too many connections]\n");
337
for (client = client_list; client && client->fd != -1;
338
client = client->next)
342
client = xcalloc (1, sizeof *client);
343
client->next = client_list;
344
client_list = client;
347
printf ("[client at fd %d connected]\n", client->fd);
350
for (client = client_list; client; client = client->next)
351
if (client->fd != -1 && FD_ISSET (client->fd, &rfds))
356
n = read (client->fd, line, sizeof line - 1);
359
int save_errno = errno;
360
print_line (client, NULL); /* flush */
361
printf ("[client at fd %d read error: %s]\n",
362
client->fd, strerror (save_errno));
368
print_line (client, NULL); /* flush */
370
printf ("[client at fd %d disconnected]\n", client->fd);
376
print_line (client, line);
387
compile-command: "gcc -Wall -g -o watchgnupg watchgnupg.c"