~ubuntu-branches/ubuntu/precise/gnupg2/precise-proposed

« back to all changes in this revision

Viewing changes to tools/watchgnupg.c

  • Committer: Bazaar Package Importer
  • Author(s): Andreas Mueller
  • Date: 2005-03-29 10:30:32 UTC
  • Revision ID: james.westby@ubuntu.com-20050329103032-sj42n2ain3ipx310
Tags: upstream-1.9.15
ImportĀ upstreamĀ versionĀ 1.9.15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* watchgnupg.c - Socket server for GnuPG logs
 
2
 *      Copyright (C) 2003, 2004 Free Software Foundation, Inc.
 
3
 *
 
4
 * This file is part of GnuPG.
 
5
 *
 
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.
 
10
 *
 
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.
 
15
 *
 
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
 
19
 */
 
20
 
 
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>
 
36
 
 
37
#define PGM "watchgnupg"
 
38
 
 
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
 
47
 
 
48
static int verbose;
 
49
 
 
50
 
 
51
static void
 
52
die (const char *format, ...)
 
53
{
 
54
  va_list arg_ptr;
 
55
 
 
56
  fflush (stdout);
 
57
  fprintf (stderr, "%s: ", PGM);
 
58
 
 
59
  va_start (arg_ptr, format);
 
60
  vfprintf (stderr, format, arg_ptr);
 
61
  va_end (arg_ptr);
 
62
  putc ('\n', stderr);
 
63
 
 
64
  exit (1);
 
65
}
 
66
 
 
67
 
 
68
/* static void */
 
69
/* err (const char *format, ...) */
 
70
/* { */
 
71
/*   va_list arg_ptr; */
 
72
 
 
73
/*   fflush (stdout); */
 
74
/*   fprintf (stderr, "%s: ", PGM); */
 
75
 
 
76
/*   va_start (arg_ptr, format); */
 
77
/*   vfprintf (stderr, format, arg_ptr); */
 
78
/*   va_end (arg_ptr); */
 
79
/*   putc ('\n', stderr); */
 
80
/* } */
 
81
 
 
82
static void *
 
83
xmalloc (size_t n)
 
84
{
 
85
  void *p = malloc (n);
 
86
  if (!p)
 
87
    die ("out of core");
 
88
  return p;
 
89
}
 
90
 
 
91
static void *
 
92
xcalloc (size_t n, size_t m)
 
93
{
 
94
  void *p = calloc (n, m);
 
95
  if (!p)
 
96
    die ("out of core");
 
97
  return p;
 
98
}
 
99
 
 
100
static void *
 
101
xrealloc (void *old, size_t n)
 
102
{
 
103
  void *p = realloc (old, n);
 
104
  if (!p)
 
105
    die ("out of core");
 
106
  return p;
 
107
}
 
108
    
 
109
 
 
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. */
 
116
  
 
117
};
 
118
typedef struct client_s *client_t;
 
119
 
 
120
 
 
121
 
 
122
static void
 
123
print_fd_and_time (int fd)
 
124
{
 
125
  struct tm *tp;
 
126
  time_t atime = time (NULL);
 
127
  
 
128
  tp = localtime (&atime);
 
129
  printf ("%3d - %04d-%02d-%02d %02d:%02d:%02d ",
 
130
          fd,
 
131
          1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday,
 
132
          tp->tm_hour, tp->tm_min, tp->tm_sec );
 
133
}
 
134
 
 
135
 
 
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)
 
140
{
 
141
  const char *s;
 
142
  size_t n;
 
143
 
 
144
  if (!line)
 
145
    {
 
146
      if (c->buffer && c->len)
 
147
        {
 
148
          print_fd_and_time (c->fd);
 
149
          fwrite (c->buffer, c->len, 1, stdout); 
 
150
          putc ('\n', stdout);
 
151
          c->len = 0;
 
152
        }
 
153
      return;
 
154
    }
 
155
 
 
156
  while ((s = strchr (line, '\n')))
 
157
    {
 
158
      print_fd_and_time (c->fd);
 
159
      if (c->buffer && c->len)
 
160
        {
 
161
          fwrite (c->buffer, c->len, 1, stdout); 
 
162
          c->len = 0;
 
163
        }
 
164
      fwrite (line, s - line + 1, 1, stdout); 
 
165
      line = s + 1;
 
166
    }
 
167
  n = strlen (line);
 
168
  if (n)
 
169
    {
 
170
      if (c->len + n >= c->size)
 
171
        {
 
172
          c->size += ((n + 255) & ~255);
 
173
          c->buffer = (c->buffer
 
174
                       ? xrealloc (c->buffer, c->size)
 
175
                       : xmalloc (c->size));
 
176
        }
 
177
      memcpy (c->buffer + c->len, line, n);
 
178
      c->len += n;
 
179
    }
 
180
}
 
181
 
 
182
 
 
183
static void
 
184
print_version (int with_help)
 
185
{
 
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);
 
192
        
 
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 );
 
203
  
 
204
  exit (0);
 
205
}
 
206
 
 
207
int 
 
208
main (int argc, char **argv)
 
209
{
 
210
  int last_argc = -1;
 
211
  int force = 0;
 
212
 
 
213
  struct sockaddr_un srvr_addr;
 
214
  int addrlen;
 
215
  int server;
 
216
  int flags;
 
217
  client_t client_list = NULL;
 
218
 
 
219
  if (argc)
 
220
    {
 
221
      argc--; argv++;
 
222
    }
 
223
  while (argc && last_argc != argc )
 
224
    {
 
225
      last_argc = argc;
 
226
      if (!strcmp (*argv, "--"))
 
227
        {
 
228
          argc--; argv++;
 
229
          break;
 
230
        }
 
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"))
 
236
        {
 
237
          verbose = 1;
 
238
          argc--; argv++;
 
239
        }
 
240
      else if (!strcmp (*argv, "--force"))
 
241
        {
 
242
          force = 1;
 
243
          argc--; argv++;
 
244
        }
 
245
    }          
 
246
 
 
247
  if (argc != 1)
 
248
    {
 
249
      fprintf (stderr, "usage: " PGM " socketname\n");
 
250
      exit (1);
 
251
    }
 
252
 
 
253
 
 
254
  if (verbose)
 
255
    fprintf (stderr, "opening socket `%s'\n", *argv);
 
256
 
 
257
  setvbuf (stdout, NULL, _IOLBF, 0);
 
258
 
 
259
  server = socket (PF_LOCAL, SOCK_STREAM, 0);
 
260
  if (server == -1)
 
261
    die ("socket() failed: %s\n", strerror (errno));
 
262
 
 
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));
 
271
  
 
272
 
 
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);
 
279
 
 
280
  
 
281
 again:
 
282
  if (bind (server, (struct sockaddr *) &srvr_addr, addrlen))
 
283
    { 
 
284
      if (errno == EADDRINUSE && force)
 
285
        {
 
286
          force = 0;
 
287
          remove (srvr_addr.sun_path);
 
288
          goto again;
 
289
        }
 
290
      die ("bind to `%s' failed: %s\n", *argv, strerror (errno));
 
291
    }
 
292
 
 
293
  if (listen (server, 5))
 
294
    die ("listen failed: %s\n", strerror (errno));
 
295
 
 
296
  for (;;)
 
297
    {
 
298
      fd_set rfds;
 
299
      int max_fd;
 
300
      client_t client;
 
301
 
 
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)
 
310
          {
 
311
            FD_SET (client->fd, &rfds);
 
312
            if (client->fd > max_fd)
 
313
              max_fd = client->fd;
 
314
          }
 
315
 
 
316
      if (select (max_fd + 1, &rfds, NULL, NULL, NULL) <= 0)
 
317
        continue;  /* Ignore any errors. */
 
318
 
 
319
      if (FD_ISSET (server, &rfds)) /* New connection. */
 
320
        { 
 
321
          struct sockaddr_un clnt_addr;
 
322
          int fd;
 
323
 
 
324
          addrlen = sizeof clnt_addr;
 
325
          fd = accept (server, (struct sockaddr *) &clnt_addr, &addrlen);
 
326
          if (fd == -1)
 
327
            {
 
328
              printf ("[accepting connection failed: %s]\n", strerror (errno));
 
329
            }
 
330
          else if (fd >= FD_SETSIZE)
 
331
            {
 
332
              close (fd);
 
333
              printf ("[connection request denied: too many connections]\n");
 
334
            }
 
335
          else 
 
336
            {
 
337
              for (client = client_list; client && client->fd != -1;
 
338
                   client = client->next)
 
339
                ;
 
340
              if (!client)
 
341
                {
 
342
                  client = xcalloc (1, sizeof *client);
 
343
                  client->next = client_list;
 
344
                  client_list = client;
 
345
                }
 
346
              client->fd = fd;
 
347
              printf ("[client at fd %d connected]\n", client->fd);
 
348
            }
 
349
        }
 
350
      for (client = client_list; client; client = client->next)
 
351
        if (client->fd != -1 && FD_ISSET (client->fd, &rfds))
 
352
          {
 
353
            char line[256];
 
354
            int n;
 
355
            
 
356
            n = read (client->fd, line, sizeof line - 1);
 
357
            if (n < 0)
 
358
              {
 
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;
 
365
              }
 
366
            else if (!n) 
 
367
              {
 
368
                print_line (client, NULL); /* flush */
 
369
                close (client->fd);
 
370
                printf ("[client at fd %d disconnected]\n", client->fd);
 
371
                client->fd = -1;
 
372
              }
 
373
            else
 
374
              {
 
375
                line[n] = 0;
 
376
                print_line (client, line);
 
377
              }
 
378
          }
 
379
    }
 
380
 
 
381
  return 0;
 
382
}
 
383
 
 
384
 
 
385
/*
 
386
Local Variables:
 
387
compile-command: "gcc -Wall -g -o watchgnupg watchgnupg.c"
 
388
End:
 
389
*/