Fixed EOF detection for encrypted packets.
[gnupg.git] / tools / watchgnupg.c
blob145a76b5e6ad5c7737e3923ed644115ef14e221d
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 3 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, see <http://www.gnu.org/licenses/>.
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <stddef.h>
26 #include <string.h>
27 #include <errno.h>
28 #include <stdarg.h>
29 #include <assert.h>
30 #include <unistd.h>
31 #include <sys/socket.h>
32 #include <sys/un.h>
33 #include <fcntl.h>
34 #include <time.h>
36 #define PGM "watchgnupg"
38 /* Allow for a standalone build on most systems. */
39 #ifdef VERSION
40 #define MYVERSION_LINE PGM " (GnuPG) " VERSION
41 #define BUGREPORT_LINE "\nReport bugs to <bug-gnupg@gnu.org>.\n"
42 #else
43 #define MYVERSION_LINE PGM
44 #define BUGREPORT_LINE ""
45 #endif
46 #if !defined(SUN_LEN) || !defined(PF_LOCAL) || !defined(AF_LOCAL)
47 #define JNLIB_NEED_AFLOCAL
48 #include "../jnlib/mischelp.h"
49 #endif
52 static int verbose;
55 static void
56 die (const char *format, ...)
58 va_list arg_ptr;
60 fflush (stdout);
61 fprintf (stderr, "%s: ", PGM);
63 va_start (arg_ptr, format);
64 vfprintf (stderr, format, arg_ptr);
65 va_end (arg_ptr);
66 putc ('\n', stderr);
68 exit (1);
72 /* static void */
73 /* err (const char *format, ...) */
74 /* { */
75 /* va_list arg_ptr; */
77 /* fflush (stdout); */
78 /* fprintf (stderr, "%s: ", PGM); */
80 /* va_start (arg_ptr, format); */
81 /* vfprintf (stderr, format, arg_ptr); */
82 /* va_end (arg_ptr); */
83 /* putc ('\n', stderr); */
84 /* } */
86 static void *
87 xmalloc (size_t n)
89 void *p = malloc (n);
90 if (!p)
91 die ("out of core");
92 return p;
95 static void *
96 xcalloc (size_t n, size_t m)
98 void *p = calloc (n, m);
99 if (!p)
100 die ("out of core");
101 return p;
104 static void *
105 xrealloc (void *old, size_t n)
107 void *p = realloc (old, n);
108 if (!p)
109 die ("out of core");
110 return p;
114 struct client_s {
115 struct client_s *next;
116 int fd;
117 size_t size; /* Allocated size of buffer. */
118 size_t len; /* Current length of buffer. */
119 unsigned char *buffer; /* Buffer to with data already read. */
122 typedef struct client_s *client_t;
126 static void
127 print_fd_and_time (int fd)
129 struct tm *tp;
130 time_t atime = time (NULL);
132 tp = localtime (&atime);
133 printf ("%3d - %04d-%02d-%02d %02d:%02d:%02d ",
135 1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday,
136 tp->tm_hour, tp->tm_min, tp->tm_sec );
140 /* Print LINE for the client identified by C. Calling this function
141 witgh LINE set to NULL, will flush the internal buffer. */
142 static void
143 print_line (client_t c, const char *line)
145 const char *s;
146 size_t n;
148 if (!line)
150 if (c->buffer && c->len)
152 print_fd_and_time (c->fd);
153 fwrite (c->buffer, c->len, 1, stdout);
154 putc ('\n', stdout);
155 c->len = 0;
157 return;
160 while ((s = strchr (line, '\n')))
162 print_fd_and_time (c->fd);
163 if (c->buffer && c->len)
165 fwrite (c->buffer, c->len, 1, stdout);
166 c->len = 0;
168 fwrite (line, s - line + 1, 1, stdout);
169 line = s + 1;
171 n = strlen (line);
172 if (n)
174 if (c->len + n >= c->size)
176 c->size += ((n + 255) & ~255);
177 c->buffer = (c->buffer
178 ? xrealloc (c->buffer, c->size)
179 : xmalloc (c->size));
181 memcpy (c->buffer + c->len, line, n);
182 c->len += n;
187 static void
188 print_version (int with_help)
190 fputs (MYVERSION_LINE "\n"
191 "Copyright (C) 2004 Free Software Foundation, Inc.\n"
192 "This program comes with ABSOLUTELY NO WARRANTY.\n"
193 "This is free software, and you are welcome to redistribute it\n"
194 "under certain conditions. See the file COPYING for details.\n",
195 stdout);
197 if (with_help)
198 fputs ("\n"
199 "Usage: " PGM " [OPTIONS] SOCKETNAME\n"
200 "Open the local socket SOCKETNAME and display log messages\n"
201 "\n"
202 " --force delete an already existing socket file\n"
203 " --verbose enable extra informational output\n"
204 " --version print version of the program and exit\n"
205 " --help display this help and exit\n"
206 BUGREPORT_LINE, stdout );
208 exit (0);
211 int
212 main (int argc, char **argv)
214 int last_argc = -1;
215 int force = 0;
217 struct sockaddr_un srvr_addr;
218 socklen_t addrlen;
219 int server;
220 int flags;
221 client_t client_list = NULL;
223 if (argc)
225 argc--; argv++;
227 while (argc && last_argc != argc )
229 last_argc = argc;
230 if (!strcmp (*argv, "--"))
232 argc--; argv++;
233 break;
235 else if (!strcmp (*argv, "--version"))
236 print_version (0);
237 else if (!strcmp (*argv, "--help"))
238 print_version (1);
239 else if (!strcmp (*argv, "--verbose"))
241 verbose = 1;
242 argc--; argv++;
244 else if (!strcmp (*argv, "--force"))
246 force = 1;
247 argc--; argv++;
251 if (argc != 1)
253 fprintf (stderr, "usage: " PGM " socketname\n");
254 exit (1);
258 if (verbose)
259 fprintf (stderr, "opening socket `%s'\n", *argv);
261 setvbuf (stdout, NULL, _IOLBF, 0);
263 server = socket (PF_LOCAL, SOCK_STREAM, 0);
264 if (server == -1)
265 die ("socket() failed: %s\n", strerror (errno));
267 /* We better set the listening socket to non-blocking so that we
268 don't get bitten by race conditions in accept. The should not
269 happen for Unix Domain sockets but well, shit happens. */
270 flags = fcntl (server, F_GETFL, 0);
271 if (flags == -1)
272 die ("fcntl (F_GETFL) failed: %s\n", strerror (errno));
273 if ( fcntl (server, F_SETFL, (flags | O_NONBLOCK)) == -1)
274 die ("fcntl (F_SETFL) failed: %s\n", strerror (errno));
277 memset (&srvr_addr, 0, sizeof srvr_addr);
278 srvr_addr.sun_family = AF_LOCAL;
279 strncpy (srvr_addr.sun_path, *argv, sizeof (srvr_addr.sun_path) - 1);
280 srvr_addr.sun_path[sizeof (srvr_addr.sun_path) - 1] = 0;
281 addrlen = SUN_LEN (&srvr_addr);
284 again:
285 if (bind (server, (struct sockaddr *) &srvr_addr, addrlen))
287 if (errno == EADDRINUSE && force)
289 force = 0;
290 remove (srvr_addr.sun_path);
291 goto again;
293 die ("bind to `%s' failed: %s\n", *argv, strerror (errno));
296 if (listen (server, 5))
297 die ("listen failed: %s\n", strerror (errno));
299 for (;;)
301 fd_set rfds;
302 int max_fd;
303 client_t client;
305 /* Usually we don't have that many connections, thus it is okay
306 to set them allways from scratch and don't maintain an active
307 fd_set. */
308 FD_ZERO (&rfds);
309 FD_SET (server, &rfds);
310 max_fd = server;
311 for (client = client_list; client; client = client->next)
312 if (client->fd != -1)
314 FD_SET (client->fd, &rfds);
315 if (client->fd > max_fd)
316 max_fd = client->fd;
319 if (select (max_fd + 1, &rfds, NULL, NULL, NULL) <= 0)
320 continue; /* Ignore any errors. */
322 if (FD_ISSET (server, &rfds)) /* New connection. */
324 struct sockaddr_un clnt_addr;
325 int fd;
327 addrlen = sizeof clnt_addr;
328 fd = accept (server, (struct sockaddr *) &clnt_addr, &addrlen);
329 if (fd == -1)
331 printf ("[accepting connection failed: %s]\n", strerror (errno));
333 else if (fd >= FD_SETSIZE)
335 close (fd);
336 printf ("[connection request denied: too many connections]\n");
338 else
340 for (client = client_list; client && client->fd != -1;
341 client = client->next)
343 if (!client)
345 client = xcalloc (1, sizeof *client);
346 client->next = client_list;
347 client_list = client;
349 client->fd = fd;
350 printf ("[client at fd %d connected]\n", client->fd);
353 for (client = client_list; client; client = client->next)
354 if (client->fd != -1 && FD_ISSET (client->fd, &rfds))
356 char line[256];
357 int n;
359 n = read (client->fd, line, sizeof line - 1);
360 if (n < 0)
362 int save_errno = errno;
363 print_line (client, NULL); /* flush */
364 printf ("[client at fd %d read error: %s]\n",
365 client->fd, strerror (save_errno));
366 close (client->fd);
367 client->fd = -1;
369 else if (!n)
371 print_line (client, NULL); /* flush */
372 close (client->fd);
373 printf ("[client at fd %d disconnected]\n", client->fd);
374 client->fd = -1;
376 else
378 line[n] = 0;
379 print_line (client, line);
384 return 0;
389 Local Variables:
390 compile-command: "gcc -Wall -g -o watchgnupg watchgnupg.c"
391 End: