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"