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. */
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 ""
49 # define PF_LOCAL PF_UNIX
51 # define PF_LOCAL AF_UNIX
54 # define AF_LOCAL AF_UNIX
63 die (const char *format
, ...)
68 fprintf (stderr
, "%s: ", PGM
);
70 va_start (arg_ptr
, format
);
71 vfprintf (stderr
, format
, arg_ptr
);
80 /* err (const char *format, ...) */
82 /* va_list arg_ptr; */
84 /* fflush (stdout); */
85 /* fprintf (stderr, "%s: ", PGM); */
87 /* va_start (arg_ptr, format); */
88 /* vfprintf (stderr, format, arg_ptr); */
89 /* va_end (arg_ptr); */
90 /* putc ('\n', stderr); */
103 xcalloc (size_t n
, size_t m
)
105 void *p
= calloc (n
, m
);
112 xrealloc (void *old
, size_t n
)
114 void *p
= realloc (old
, n
);
122 struct client_s
*next
;
124 size_t size
; /* Allocated size of buffer. */
125 size_t len
; /* Current length of buffer. */
126 unsigned char *buffer
; /* Buffer to with data already read. */
129 typedef struct client_s
*client_t
;
134 print_fd_and_time (int fd
)
137 time_t atime
= time (NULL
);
139 tp
= localtime (&atime
);
140 printf ("%3d - %04d-%02d-%02d %02d:%02d:%02d ",
142 1900+tp
->tm_year
, tp
->tm_mon
+1, tp
->tm_mday
,
143 tp
->tm_hour
, tp
->tm_min
, tp
->tm_sec
);
147 /* Print LINE for the client identified by C. Calling this function
148 witgh LINE set to NULL, will flush the internal buffer. */
150 print_line (client_t c
, const char *line
)
157 if (c
->buffer
&& c
->len
)
159 print_fd_and_time (c
->fd
);
160 fwrite (c
->buffer
, c
->len
, 1, stdout
);
167 while ((s
= strchr (line
, '\n')))
169 print_fd_and_time (c
->fd
);
170 if (c
->buffer
&& c
->len
)
172 fwrite (c
->buffer
, c
->len
, 1, stdout
);
175 fwrite (line
, s
- line
+ 1, 1, stdout
);
181 if (c
->len
+ n
>= c
->size
)
183 c
->size
+= ((n
+ 255) & ~255);
184 c
->buffer
= (c
->buffer
185 ? xrealloc (c
->buffer
, c
->size
)
186 : xmalloc (c
->size
));
188 memcpy (c
->buffer
+ c
->len
, line
, n
);
195 print_version (int with_help
)
197 fputs (MYVERSION_LINE
"\n"
198 "Copyright (C) 2004 Free Software Foundation, Inc.\n"
199 "This program comes with ABSOLUTELY NO WARRANTY.\n"
200 "This is free software, and you are welcome to redistribute it\n"
201 "under certain conditions. See the file COPYING for details.\n",
206 "Usage: " PGM
" [OPTIONS] SOCKETNAME\n"
207 "Open the local socket SOCKETNAME and display log messages\n"
209 " --force delete an already existing socket file\n"
210 " --verbose enable extra informational output\n"
211 " --version print version of the program and exit\n"
212 " --help display this help and exit\n"
213 BUGREPORT_LINE
, stdout
);
219 main (int argc
, char **argv
)
224 struct sockaddr_un srvr_addr
;
228 client_t client_list
= NULL
;
234 while (argc
&& last_argc
!= argc
)
237 if (!strcmp (*argv
, "--"))
242 else if (!strcmp (*argv
, "--version"))
244 else if (!strcmp (*argv
, "--help"))
246 else if (!strcmp (*argv
, "--verbose"))
251 else if (!strcmp (*argv
, "--force"))
260 fprintf (stderr
, "usage: " PGM
" socketname\n");
266 fprintf (stderr
, "opening socket `%s'\n", *argv
);
268 setvbuf (stdout
, NULL
, _IOLBF
, 0);
270 server
= socket (PF_LOCAL
, SOCK_STREAM
, 0);
272 die ("socket() failed: %s\n", strerror (errno
));
274 /* We better set the listening socket to non-blocking so that we
275 don't get bitten by race conditions in accept. The should not
276 happen for Unix Domain sockets but well, shit happens. */
277 flags
= fcntl (server
, F_GETFL
, 0);
279 die ("fcntl (F_GETFL) failed: %s\n", strerror (errno
));
280 if ( fcntl (server
, F_SETFL
, (flags
| O_NONBLOCK
)) == -1)
281 die ("fcntl (F_SETFL) failed: %s\n", strerror (errno
));
284 memset (&srvr_addr
, 0, sizeof srvr_addr
);
285 srvr_addr
.sun_family
= AF_LOCAL
;
286 strncpy (srvr_addr
.sun_path
, *argv
, sizeof (srvr_addr
.sun_path
) - 1);
287 srvr_addr
.sun_path
[sizeof (srvr_addr
.sun_path
) - 1] = 0;
288 addrlen
= (offsetof (struct sockaddr_un
, sun_path
)
289 + strlen (srvr_addr
.sun_path
) + 1);
293 if (bind (server
, (struct sockaddr
*) &srvr_addr
, addrlen
))
295 if (errno
== EADDRINUSE
&& force
)
298 remove (srvr_addr
.sun_path
);
301 die ("bind to `%s' failed: %s\n", *argv
, strerror (errno
));
304 if (listen (server
, 5))
305 die ("listen failed: %s\n", strerror (errno
));
313 /* Usually we don't have that many connections, thus it is okay
314 to set them allways from scratch and don't maintain an active
317 FD_SET (server
, &rfds
);
319 for (client
= client_list
; client
; client
= client
->next
)
320 if (client
->fd
!= -1)
322 FD_SET (client
->fd
, &rfds
);
323 if (client
->fd
> max_fd
)
327 if (select (max_fd
+ 1, &rfds
, NULL
, NULL
, NULL
) <= 0)
328 continue; /* Ignore any errors. */
330 if (FD_ISSET (server
, &rfds
)) /* New connection. */
332 struct sockaddr_un clnt_addr
;
335 addrlen
= sizeof clnt_addr
;
336 fd
= accept (server
, (struct sockaddr
*) &clnt_addr
, &addrlen
);
339 printf ("[accepting connection failed: %s]\n", strerror (errno
));
341 else if (fd
>= FD_SETSIZE
)
344 printf ("[connection request denied: too many connections]\n");
348 for (client
= client_list
; client
&& client
->fd
!= -1;
349 client
= client
->next
)
353 client
= xcalloc (1, sizeof *client
);
354 client
->next
= client_list
;
355 client_list
= client
;
358 printf ("[client at fd %d connected]\n", client
->fd
);
361 for (client
= client_list
; client
; client
= client
->next
)
362 if (client
->fd
!= -1 && FD_ISSET (client
->fd
, &rfds
))
367 n
= read (client
->fd
, line
, sizeof line
- 1);
370 int save_errno
= errno
;
371 print_line (client
, NULL
); /* flush */
372 printf ("[client at fd %d read error: %s]\n",
373 client
->fd
, strerror (save_errno
));
379 print_line (client
, NULL
); /* flush */
381 printf ("[client at fd %d disconnected]\n", client
->fd
);
387 print_line (client
, line
);
398 compile-command: "gcc -Wall -g -o watchgnupg watchgnupg.c"