2005-04-11 Marcus Brinkmann <marcus@g10code.de>
[gnupg.git] / tools / watchgnupg.c
blob50f9d7274452be34a25d95e5436c8bbaeb961b3a
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
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <stddef.h>
27 #include <string.h>
28 #include <errno.h>
29 #include <stdarg.h>
30 #include <assert.h>
31 #include <unistd.h>
32 #include <sys/socket.h>
33 #include <sys/un.h>
34 #include <fcntl.h>
35 #include <time.h>
37 #define PGM "watchgnupg"
39 /* Allow for a standalone build. */
40 #ifdef VERSION
41 #define MYVERSION_LINE PGM " (GnuPG) " VERSION
42 #define BUGREPORT_LINE "\nReport bugs to <bug-gnupg@gnu.org>.\n"
43 #else
44 #define MYVERSION_LINE PGM
45 #define BUGREPORT_LINE ""
46 #endif
48 static int verbose;
51 static void
52 die (const char *format, ...)
54 va_list arg_ptr;
56 fflush (stdout);
57 fprintf (stderr, "%s: ", PGM);
59 va_start (arg_ptr, format);
60 vfprintf (stderr, format, arg_ptr);
61 va_end (arg_ptr);
62 putc ('\n', stderr);
64 exit (1);
68 /* static void */
69 /* err (const char *format, ...) */
70 /* { */
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); */
80 /* } */
82 static void *
83 xmalloc (size_t n)
85 void *p = malloc (n);
86 if (!p)
87 die ("out of core");
88 return p;
91 static void *
92 xcalloc (size_t n, size_t m)
94 void *p = calloc (n, m);
95 if (!p)
96 die ("out of core");
97 return p;
100 static void *
101 xrealloc (void *old, size_t n)
103 void *p = realloc (old, n);
104 if (!p)
105 die ("out of core");
106 return p;
110 struct client_s {
111 struct client_s *next;
112 int fd;
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;
122 static void
123 print_fd_and_time (int fd)
125 struct tm *tp;
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. */
138 static void
139 print_line (client_t c, const char *line)
141 const char *s;
142 size_t n;
144 if (!line)
146 if (c->buffer && c->len)
148 print_fd_and_time (c->fd);
149 fwrite (c->buffer, c->len, 1, stdout);
150 putc ('\n', stdout);
151 c->len = 0;
153 return;
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);
162 c->len = 0;
164 fwrite (line, s - line + 1, 1, stdout);
165 line = s + 1;
167 n = strlen (line);
168 if (n)
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);
178 c->len += n;
183 static void
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",
191 stdout);
193 if (with_help)
194 fputs ("\n"
195 "Usage: " PGM " [OPTIONS] SOCKETNAME\n"
196 "Open the local socket SOCKETNAME and display log messages\n"
197 "\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 );
204 exit (0);
207 int
208 main (int argc, char **argv)
210 int last_argc = -1;
211 int force = 0;
213 struct sockaddr_un srvr_addr;
214 int addrlen;
215 int server;
216 int flags;
217 client_t client_list = NULL;
219 if (argc)
221 argc--; argv++;
223 while (argc && last_argc != argc )
225 last_argc = argc;
226 if (!strcmp (*argv, "--"))
228 argc--; argv++;
229 break;
231 else if (!strcmp (*argv, "--version"))
232 print_version (0);
233 else if (!strcmp (*argv, "--help"))
234 print_version (1);
235 else if (!strcmp (*argv, "--verbose"))
237 verbose = 1;
238 argc--; argv++;
240 else if (!strcmp (*argv, "--force"))
242 force = 1;
243 argc--; argv++;
247 if (argc != 1)
249 fprintf (stderr, "usage: " PGM " socketname\n");
250 exit (1);
254 if (verbose)
255 fprintf (stderr, "opening socket `%s'\n", *argv);
257 setvbuf (stdout, NULL, _IOLBF, 0);
259 server = socket (PF_LOCAL, SOCK_STREAM, 0);
260 if (server == -1)
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);
267 if (flags == -1)
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);
281 again:
282 if (bind (server, (struct sockaddr *) &srvr_addr, addrlen))
284 if (errno == EADDRINUSE && force)
286 force = 0;
287 remove (srvr_addr.sun_path);
288 goto again;
290 die ("bind to `%s' failed: %s\n", *argv, strerror (errno));
293 if (listen (server, 5))
294 die ("listen failed: %s\n", strerror (errno));
296 for (;;)
298 fd_set rfds;
299 int max_fd;
300 client_t client;
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
304 fd_set. */
305 FD_ZERO (&rfds);
306 FD_SET (server, &rfds);
307 max_fd = server;
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)
313 max_fd = client->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;
322 int fd;
324 addrlen = sizeof clnt_addr;
325 fd = accept (server, (struct sockaddr *) &clnt_addr, &addrlen);
326 if (fd == -1)
328 printf ("[accepting connection failed: %s]\n", strerror (errno));
330 else if (fd >= FD_SETSIZE)
332 close (fd);
333 printf ("[connection request denied: too many connections]\n");
335 else
337 for (client = client_list; client && client->fd != -1;
338 client = client->next)
340 if (!client)
342 client = xcalloc (1, sizeof *client);
343 client->next = client_list;
344 client_list = client;
346 client->fd = fd;
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))
353 char line[256];
354 int n;
356 n = read (client->fd, line, sizeof line - 1);
357 if (n < 0)
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));
363 close (client->fd);
364 client->fd = -1;
366 else if (!n)
368 print_line (client, NULL); /* flush */
369 close (client->fd);
370 printf ("[client at fd %d disconnected]\n", client->fd);
371 client->fd = -1;
373 else
375 line[n] = 0;
376 print_line (client, line);
381 return 0;
386 Local Variables:
387 compile-command: "gcc -Wall -g -o watchgnupg watchgnupg.c"
388 End: