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 ""
50 # define PF_LOCAL PF_UNIX
52 # define PF_LOCAL AF_UNIX
55 # define AF_LOCAL AF_UNIX
64 die (const char *format
, ...)
69 fprintf (stderr
, "%s: ", PGM
);
71 va_start (arg_ptr
, format
);
72 vfprintf (stderr
, format
, arg_ptr
);
81 /* err (const char *format, ...) */
83 /* va_list arg_ptr; */
85 /* fflush (stdout); */
86 /* fprintf (stderr, "%s: ", PGM); */
88 /* va_start (arg_ptr, format); */
89 /* vfprintf (stderr, format, arg_ptr); */
90 /* va_end (arg_ptr); */
91 /* putc ('\n', stderr); */
104 xcalloc (size_t n
, size_t m
)
106 void *p
= calloc (n
, m
);
113 xrealloc (void *old
, size_t n
)
115 void *p
= realloc (old
, n
);
123 struct client_s
*next
;
125 size_t size
; /* Allocated size of buffer. */
126 size_t len
; /* Current length of buffer. */
127 unsigned char *buffer
; /* Buffer to with data already read. */
130 typedef struct client_s
*client_t
;
135 print_fd_and_time (int fd
)
138 time_t atime
= time (NULL
);
140 tp
= localtime (&atime
);
141 printf ("%3d - %04d-%02d-%02d %02d:%02d:%02d ",
143 1900+tp
->tm_year
, tp
->tm_mon
+1, tp
->tm_mday
,
144 tp
->tm_hour
, tp
->tm_min
, tp
->tm_sec
);
148 /* Print LINE for the client identified by C. Calling this function
149 witgh LINE set to NULL, will flush the internal buffer. */
151 print_line (client_t c
, const char *line
)
158 if (c
->buffer
&& c
->len
)
160 print_fd_and_time (c
->fd
);
161 fwrite (c
->buffer
, c
->len
, 1, stdout
);
168 while ((s
= strchr (line
, '\n')))
170 print_fd_and_time (c
->fd
);
171 if (c
->buffer
&& c
->len
)
173 fwrite (c
->buffer
, c
->len
, 1, stdout
);
176 fwrite (line
, s
- line
+ 1, 1, stdout
);
182 if (c
->len
+ n
>= c
->size
)
184 c
->size
+= ((n
+ 255) & ~255);
185 c
->buffer
= (c
->buffer
186 ? xrealloc (c
->buffer
, c
->size
)
187 : xmalloc (c
->size
));
189 memcpy (c
->buffer
+ c
->len
, line
, n
);
196 print_version (int with_help
)
198 fputs (MYVERSION_LINE
"\n"
199 "Copyright (C) 2004 Free Software Foundation, Inc.\n"
200 "This program comes with ABSOLUTELY NO WARRANTY.\n"
201 "This is free software, and you are welcome to redistribute it\n"
202 "under certain conditions. See the file COPYING for details.\n",
207 "Usage: " PGM
" [OPTIONS] SOCKETNAME\n"
208 "Open the local socket SOCKETNAME and display log messages\n"
210 " --force delete an already existing socket file\n"
211 " --verbose enable extra informational output\n"
212 " --version print version of the program and exit\n"
213 " --help display this help and exit\n"
214 BUGREPORT_LINE
, stdout
);
220 main (int argc
, char **argv
)
225 struct sockaddr_un srvr_addr
;
229 client_t client_list
= NULL
;
235 while (argc
&& last_argc
!= argc
)
238 if (!strcmp (*argv
, "--"))
243 else if (!strcmp (*argv
, "--version"))
245 else if (!strcmp (*argv
, "--help"))
247 else if (!strcmp (*argv
, "--verbose"))
252 else if (!strcmp (*argv
, "--force"))
261 fprintf (stderr
, "usage: " PGM
" socketname\n");
267 fprintf (stderr
, "opening socket `%s'\n", *argv
);
269 setvbuf (stdout
, NULL
, _IOLBF
, 0);
271 server
= socket (PF_LOCAL
, SOCK_STREAM
, 0);
273 die ("socket() failed: %s\n", strerror (errno
));
275 /* We better set the listening socket to non-blocking so that we
276 don't get bitten by race conditions in accept. The should not
277 happen for Unix Domain sockets but well, shit happens. */
278 flags
= fcntl (server
, F_GETFL
, 0);
280 die ("fcntl (F_GETFL) failed: %s\n", strerror (errno
));
281 if ( fcntl (server
, F_SETFL
, (flags
| O_NONBLOCK
)) == -1)
282 die ("fcntl (F_SETFL) failed: %s\n", strerror (errno
));
285 memset (&srvr_addr
, 0, sizeof srvr_addr
);
286 srvr_addr
.sun_family
= AF_LOCAL
;
287 strncpy (srvr_addr
.sun_path
, *argv
, sizeof (srvr_addr
.sun_path
) - 1);
288 srvr_addr
.sun_path
[sizeof (srvr_addr
.sun_path
) - 1] = 0;
289 addrlen
= (offsetof (struct sockaddr_un
, sun_path
)
290 + strlen (srvr_addr
.sun_path
) + 1);
294 if (bind (server
, (struct sockaddr
*) &srvr_addr
, addrlen
))
296 if (errno
== EADDRINUSE
&& force
)
299 remove (srvr_addr
.sun_path
);
302 die ("bind to `%s' failed: %s\n", *argv
, strerror (errno
));
305 if (listen (server
, 5))
306 die ("listen failed: %s\n", strerror (errno
));
314 /* Usually we don't have that many connections, thus it is okay
315 to set them allways from scratch and don't maintain an active
318 FD_SET (server
, &rfds
);
320 for (client
= client_list
; client
; client
= client
->next
)
321 if (client
->fd
!= -1)
323 FD_SET (client
->fd
, &rfds
);
324 if (client
->fd
> max_fd
)
328 if (select (max_fd
+ 1, &rfds
, NULL
, NULL
, NULL
) <= 0)
329 continue; /* Ignore any errors. */
331 if (FD_ISSET (server
, &rfds
)) /* New connection. */
333 struct sockaddr_un clnt_addr
;
336 addrlen
= sizeof clnt_addr
;
337 fd
= accept (server
, (struct sockaddr
*) &clnt_addr
, &addrlen
);
340 printf ("[accepting connection failed: %s]\n", strerror (errno
));
342 else if (fd
>= FD_SETSIZE
)
345 printf ("[connection request denied: too many connections]\n");
349 for (client
= client_list
; client
&& client
->fd
!= -1;
350 client
= client
->next
)
354 client
= xcalloc (1, sizeof *client
);
355 client
->next
= client_list
;
356 client_list
= client
;
359 printf ("[client at fd %d connected]\n", client
->fd
);
362 for (client
= client_list
; client
; client
= client
->next
)
363 if (client
->fd
!= -1 && FD_ISSET (client
->fd
, &rfds
))
368 n
= read (client
->fd
, line
, sizeof line
- 1);
371 int save_errno
= errno
;
372 print_line (client
, NULL
); /* flush */
373 printf ("[client at fd %d read error: %s]\n",
374 client
->fd
, strerror (save_errno
));
380 print_line (client
, NULL
); /* flush */
382 printf ("[client at fd %d disconnected]\n", client
->fd
);
388 print_line (client
, line
);
399 compile-command: "gcc -Wall -g -o watchgnupg watchgnupg.c"