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/>.
31 #include <sys/socket.h>
36 #define PGM "watchgnupg"
38 /* Allow for a standalone build on most systems. */
40 #define MYVERSION_LINE PGM " (GnuPG) " VERSION
41 #define BUGREPORT_LINE "\nReport bugs to <bug-gnupg@gnu.org>.\n"
43 #define MYVERSION_LINE PGM
44 #define BUGREPORT_LINE ""
46 #if !defined(SUN_LEN) || !defined(PF_LOCAL) || !defined(AF_LOCAL)
47 #define JNLIB_NEED_AFLOCAL
48 #include "../jnlib/mischelp.h"
56 die (const char *format
, ...)
61 fprintf (stderr
, "%s: ", PGM
);
63 va_start (arg_ptr
, format
);
64 vfprintf (stderr
, format
, arg_ptr
);
73 /* err (const char *format, ...) */
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); */
96 xcalloc (size_t n
, size_t m
)
98 void *p
= calloc (n
, m
);
105 xrealloc (void *old
, size_t n
)
107 void *p
= realloc (old
, n
);
115 struct client_s
*next
;
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
;
127 print_fd_and_time (int fd
)
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. */
143 print_line (client_t c
, const char *line
)
150 if (c
->buffer
&& c
->len
)
152 print_fd_and_time (c
->fd
);
153 fwrite (c
->buffer
, c
->len
, 1, stdout
);
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
);
168 fwrite (line
, s
- line
+ 1, 1, stdout
);
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
);
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",
199 "Usage: " PGM
" [OPTIONS] SOCKETNAME\n"
200 "Open the local socket SOCKETNAME and display log messages\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
);
212 main (int argc
, char **argv
)
217 struct sockaddr_un srvr_addr
;
221 client_t client_list
= NULL
;
227 while (argc
&& last_argc
!= argc
)
230 if (!strcmp (*argv
, "--"))
235 else if (!strcmp (*argv
, "--version"))
237 else if (!strcmp (*argv
, "--help"))
239 else if (!strcmp (*argv
, "--verbose"))
244 else if (!strcmp (*argv
, "--force"))
253 fprintf (stderr
, "usage: " PGM
" socketname\n");
259 fprintf (stderr
, "opening socket `%s'\n", *argv
);
261 setvbuf (stdout
, NULL
, _IOLBF
, 0);
263 server
= socket (PF_LOCAL
, SOCK_STREAM
, 0);
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);
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
);
285 if (bind (server
, (struct sockaddr
*) &srvr_addr
, addrlen
))
287 if (errno
== EADDRINUSE
&& force
)
290 remove (srvr_addr
.sun_path
);
293 die ("bind to `%s' failed: %s\n", *argv
, strerror (errno
));
296 if (listen (server
, 5))
297 die ("listen failed: %s\n", strerror (errno
));
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
309 FD_SET (server
, &rfds
);
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
)
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
;
327 addrlen
= sizeof clnt_addr
;
328 fd
= accept (server
, (struct sockaddr
*) &clnt_addr
, &addrlen
);
331 printf ("[accepting connection failed: %s]\n", strerror (errno
));
333 else if (fd
>= FD_SETSIZE
)
336 printf ("[connection request denied: too many connections]\n");
340 for (client
= client_list
; client
&& client
->fd
!= -1;
341 client
= client
->next
)
345 client
= xcalloc (1, sizeof *client
);
346 client
->next
= client_list
;
347 client_list
= client
;
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
))
359 n
= read (client
->fd
, line
, sizeof line
- 1);
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
));
371 print_line (client
, NULL
); /* flush */
373 printf ("[client at fd %d disconnected]\n", client
->fd
);
379 print_line (client
, line
);
390 compile-command: "gcc -Wall -g -o watchgnupg watchgnupg.c"