Merge from vendor branch BIND:
[dragonfly.git] / contrib / cvs-1.12 / src / log-buffer.c
1 /* CVS client logging buffer.
2
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License as published by
5    the Free Software Foundation; either version 2, or (at your option)
6    any later version.
7
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.  */
12
13 #include <config.h>
14
15 #include <stdio.h>
16
17 #include "cvs.h"
18 #include "buffer.h"
19
20 #if defined CLIENT_SUPPORT || defined SERVER_SUPPORT
21
22 /* We want to be able to log data sent between us and the server.  We
23    do it using log buffers.  Each log buffer has another buffer which
24    handles the actual I/O, and a file to log information to.
25
26    This structure is the closure field of a log buffer.  */
27
28 struct log_buffer
29 {
30     /* The underlying buffer.  */
31     struct buffer *buf;
32     /* The file to log information to.  */
33     FILE *log;
34
35 #ifdef PROXY_SUPPORT
36     /* Whether errors writing to the log file should be fatal or not.  */
37     bool fatal_errors;
38
39     /* The name of the file backing this buffer so that it may be deleted on
40      * buffer shutdown.
41      */
42     char *back_fn;
43
44     /* Set once logging is permanently disabled for a buffer.  */
45     bool disabled;
46
47     /* The memory buffer (cache) backing this log.  */
48     struct buffer *back_buf;
49
50     /* The maximum number of bytes to store in memory before beginning logging
51      * to a file.
52      */
53     size_t max;
54
55     /* Once we start logging to a file we do not want to stop unless asked.  */
56     bool tofile;
57 #endif /* PROXY_SUPPORT */
58 };
59
60
61
62 #ifdef PROXY_SUPPORT
63 /* Force the existance of lb->log.
64  *
65  * INPUTS
66  *   lb                 The log buffer.
67  *
68  * OUTPUTS
69  *   lb->log            The new FILE *.
70  *   lb->back_fn        The name of the new log, for later disposal.
71  *
72  * ASSUMPTIONS
73  *   lb->log is NULL or, at least, does not require freeing.
74  *   lb->back_fn is NULL or, at least, does not require freeing..
75  *
76  * RETURNS
77  *   Nothing.
78  *
79  * ERRORS
80  *   Errors creating the log file will output a message via error().  Whether
81  *   the error is fatal or not is dependent on lb->fatal_errors.
82  */
83 static inline void
84 log_buffer_force_file (struct log_buffer *lb)
85 {
86     lb->log = cvs_temp_file (&lb->back_fn);
87     if (!lb->log)
88         error (lb->fatal_errors, errno, "failed to open log file.");
89 }
90 #endif /* PROXY_SUPPORT */
91
92
93
94 /* Create a log buffer.
95  *
96  * INPUTS
97  *   buf                A pointer to the buffer structure to log input from.
98  *   fp                 A file name to log data to.  May be NULL.
99 #ifdef PROXY_SUPPORT
100  *   fatal_errors       Whether errors writing to a log file should be
101  *                      considered fatal.
102 #else
103  *   fatal_errors       unused
104 #endif
105  *   input              Whether we will log data for an input or output
106  *                      buffer.
107 #ifdef PROXY_SUPPORT
108  *   max                The maximum size of our memory cache.
109 #else
110  *   max                unused
111 #endif
112  *   memory             The function to call when memory allocation errors are
113  *                      encountered.
114  *
115  * RETURNS
116  *   A pointer to a new buffer structure.
117  */
118 static int log_buffer_input (void *, char *, size_t, size_t, size_t *);
119 static int log_buffer_output (void *, const char *, size_t, size_t *);
120 static int log_buffer_flush (void *);
121 static int log_buffer_block (void *, bool);
122 static int log_buffer_get_fd (void *);
123 static int log_buffer_shutdown (struct buffer *);
124 struct buffer *
125 log_buffer_initialize (struct buffer *buf, FILE *fp,
126 # ifdef PROXY_SUPPORT
127                        bool fatal_errors,
128                        size_t max,
129 # endif /* PROXY_SUPPORT */
130                        bool input,
131                        void (*memory) (struct buffer *))
132 {
133     struct log_buffer *lb = xmalloc (sizeof *lb);
134     struct buffer *retbuf;
135
136     lb->buf = buf;
137     lb->log = fp;
138 #ifdef PROXY_SUPPORT
139     lb->back_fn = NULL;
140     lb->fatal_errors = fatal_errors;
141     lb->disabled = false;
142     assert (size_in_bounds_p (max));
143     lb->max = max;
144     lb->tofile = false;
145     lb->back_buf = buf_nonio_initialize (memory);
146 #endif /* PROXY_SUPPORT */
147     retbuf = buf_initialize (input ? log_buffer_input : NULL,
148                              input ? NULL : log_buffer_output,
149                              input ? NULL : log_buffer_flush,
150                              log_buffer_block, log_buffer_get_fd,
151                              log_buffer_shutdown, memory, lb);
152
153     if (!buf_empty_p (buf))
154     {
155         /* If our buffer already had data, copy it & log it if necessary.  This
156          * can happen, for instance, with a pserver, where we deliberately do
157          * not instantiate the log buffer until after authentication so that
158          * auth data does not get logged (the pserver data will not be logged
159          * in this case, but any data which was left unused in the buffer by
160          * the auth code will be logged and put in our new buffer).
161          */
162         struct buffer_data *data;
163 #ifdef PROXY_SUPPORT
164         size_t total = 0;
165 #endif /* PROXY_SUPPORT */
166
167         for (data = buf->data; data != NULL; data = data->next)
168         {
169 #ifdef PROXY_SUPPORT
170             if (!lb->tofile)
171             {
172                 total = xsum (data->size, total);
173                 if (total >= max)
174                     lb->tofile = true;
175             }
176
177             if (lb->tofile)
178             {
179                 if (!lb->log) log_buffer_force_file (lb);
180                 if (lb->log)
181                 {
182 #endif /* PROXY_SUPPORT */
183                     if (fwrite (data->bufp, 1, data->size, lb->log)
184                         != (size_t) data->size)
185                         error (
186 #ifdef PROXY_SUPPORT
187                                fatal_errors,
188 #else /* !PROXY_SUPPORT */
189                                false,
190 #endif /* PROXY_SUPPORT */
191                                errno, "writing to log file");
192                     fflush (lb->log);
193 #ifdef PROXY_SUPPORT
194                 }
195             }
196             else
197                 /* Log to memory buffer.  */
198                 buf_copy_data (lb->back_buf, data, data);
199 #endif /* PROXY_SUPPORT */
200         }
201         buf_append_buffer (retbuf, buf);
202     }
203     return retbuf;
204 }
205
206
207
208 /* The input function for a log buffer.  */
209 static int
210 log_buffer_input (void *closure, char *data, size_t need, size_t size,
211                   size_t *got)
212 {
213     struct log_buffer *lb = closure;
214     int status;
215
216     assert (lb->buf->input);
217
218     status = (*lb->buf->input) (lb->buf->closure, data, need, size, got);
219     if (status != 0)
220         return status;
221
222     if (
223 #ifdef PROXY_SUPPORT
224         !lb->disabled &&
225 #endif /* PROXY_SUPPORT */
226         *got > 0)
227     {
228 #ifdef PROXY_SUPPORT
229         if (!lb->tofile
230             && xsum (*got, buf_count_mem (lb->back_buf)) >= lb->max)
231             lb->tofile = true;
232
233         if (lb->tofile)
234         {
235             if (!lb->log) log_buffer_force_file (lb);
236             if (lb->log)
237             {
238 #endif /* PROXY_SUPPORT */
239                 if (fwrite (data, 1, *got, lb->log) != *got)
240                     error (
241 #ifdef PROXY_SUPPORT
242                            lb->fatal_errors,
243 #else /* !PROXY_SUPPORT */
244                            false,
245 #endif /* PROXY_SUPPORT */
246                            errno, "writing to log file");
247                 fflush (lb->log);
248 #ifdef PROXY_SUPPORT
249             }
250         }
251         else
252             /* Log to memory buffer.  */
253             buf_output (lb->back_buf, data, *got);
254 #endif /* PROXY_SUPPORT */
255     }
256
257     return 0;
258 }
259
260
261
262 /* The output function for a log buffer.  */
263 static int
264 log_buffer_output (void *closure, const char *data, size_t have, size_t *wrote)
265 {
266     struct log_buffer *lb = closure;
267     int status;
268
269     assert (lb->buf->output);
270
271     status = (*lb->buf->output) (lb->buf->closure, data, have, wrote);
272     if (status != 0)
273         return status;
274
275     if (
276 #ifdef PROXY_SUPPORT
277         !lb->disabled &&
278 #endif /* PROXY_SUPPORT */
279         *wrote > 0)
280     {
281 #ifdef PROXY_SUPPORT
282         if (!lb->tofile
283             && xsum (*wrote, buf_count_mem (lb->back_buf)) >= lb->max)
284             lb->tofile = true;
285
286         if (lb->tofile)
287         {
288             if (!lb->log) log_buffer_force_file (lb);
289             if (lb->log)
290             {
291 #endif /* PROXY_SUPPORT */
292                 if (fwrite (data, 1, *wrote, lb->log) != *wrote)
293                     error (
294 #ifdef PROXY_SUPPORT
295                            lb->fatal_errors,
296 #else /* !PROXY_SUPPORT */
297                            false,
298 #endif /* PROXY_SUPPORT */
299                            errno, "writing to log file");
300                 fflush (lb->log);
301 #ifdef PROXY_SUPPORT
302             }
303         }
304         else
305             /* Log to memory buffer.  */
306             buf_output (lb->back_buf, data, *wrote);
307 #endif /* PROXY_SUPPORT */
308     }
309
310     return 0;
311 }
312
313
314
315 /* The flush function for a log buffer.  */
316 static int
317 log_buffer_flush (void *closure)
318 {
319     struct log_buffer *lb = closure;
320
321     assert (lb->buf->flush);
322
323     /* We don't really have to flush the log file here, but doing it
324      * will let tail -f on the log file show what is sent to the
325      * network as it is sent.
326      */
327     if (lb->log && (fflush (lb->log)))
328         error (0, errno, "flushing log file");
329
330     return (*lb->buf->flush) (lb->buf->closure);
331 }
332
333
334
335 /* The block function for a log buffer.  */
336 static int
337 log_buffer_block (void *closure, bool block)
338 {
339     struct log_buffer *lb = closure;
340
341     if (block)
342         return set_block (lb->buf);
343     else
344         return set_nonblock (lb->buf);
345 }
346
347
348
349 #ifdef PROXY_SUPPORT
350 /* Disable logging without shutting down the next buffer in the chain.
351  */
352 struct buffer *
353 log_buffer_rewind (struct buffer *buf)
354 {
355     struct log_buffer *lb = buf->closure;
356     struct buffer *retbuf;
357     int fd;
358
359     lb->disabled = true;
360
361     if (lb->log)
362     {
363         FILE *tmp = lb->log;
364         lb->log = NULL;
365
366         /* flush & rewind the file.  */
367         if (fflush (tmp) < 0)
368             error (0, errno, "flushing log file");
369         rewind (tmp);
370
371         /* Get a descriptor for the log and close the FILE *.  */
372         fd = dup (fileno (tmp));
373         if (fclose (tmp) < 0)
374             error (0, errno, "closing log file");
375     }
376     else
377         fd = open (DEVNULL, O_RDONLY);
378
379     /* Catch dup/open errors.  */
380     if (fd < 0)
381     {
382         error (lb->fatal_errors, errno, "failed to rewind log buf.");
383         return NULL;
384     }
385
386     /* Create a new fd buffer around the log.  */
387     retbuf = fd_buffer_initialize (fd, 0, NULL, true, buf->memory_error);
388
389     {
390         struct buffer *tmp;
391         /* Insert the data which wasn't written to a file.  */
392         buf_append_buffer (retbuf, lb->back_buf);
393         tmp = lb->back_buf;
394         lb->back_buf = NULL;
395         buf_free (tmp);
396     }
397
398     return retbuf;
399 }
400 #endif /* PROXY_SUPPORT */
401
402
403
404 /* Disable logging and close the log without shutting down the next buffer in
405  * the chain.
406  */
407 #ifndef PROXY_SUPPORT
408 static
409 #endif /* !PROXY_SUPPORT */
410 void
411 log_buffer_closelog (struct buffer *buf)
412 {
413     struct log_buffer *lb = buf->closure;
414     void *tmp;
415
416 #ifdef PROXY_SUPPORT
417     lb->disabled = true;
418 #endif /* PROXY_SUPPORT */
419
420     /* Close the log.  */
421     if (lb->log)
422     {
423         tmp = lb->log;
424         lb->log = NULL;
425         if (fclose (tmp) < 0)
426             error (0, errno, "closing log file");
427     }
428
429 #ifdef PROXY_SUPPORT
430     /* Delete the log if we know its name.  */
431     if (lb->back_fn)
432     {
433         tmp = lb->back_fn;
434         lb->back_fn = NULL;
435         if (CVS_UNLINK (tmp))
436             error (0, errno, "Failed to delete log file.");
437         free (tmp);
438     }
439
440     if (lb->back_buf)
441     {
442         tmp = lb->back_buf;
443         lb->back_buf = NULL;
444         buf_free (tmp);
445     }
446 #endif /* PROXY_SUPPORT */
447 }
448
449
450
451 /* Return the file descriptor underlying any child buffers.  */
452 static int
453 log_buffer_get_fd (void *closure)
454 {
455     struct log_buffer *lb = closure;
456     return buf_get_fd (lb->buf);
457 }
458
459
460
461 /* The shutdown function for a log buffer.  */
462 static int
463 log_buffer_shutdown (struct buffer *buf)
464 {
465     struct log_buffer *lb = buf->closure;
466
467     log_buffer_closelog (buf);
468     return buf_shutdown (lb->buf);
469 }
470
471
472
473 void
474 setup_logfiles (char *var, struct buffer **to_server_p,
475                 struct buffer **from_server_p)
476 {
477   char *log = getenv (var);
478
479   /* Set up logfiles, if any.
480    *
481    * We do this _after_ authentication on purpose.  Wouldn't really like to
482    * worry about logging passwords...
483    */
484   if (log)
485     {
486       int len = strlen (log);
487       char *buf = xmalloc (len + 5);
488       char *p;
489       FILE *fp;
490
491       strcpy (buf, log);
492       p = buf + len;
493
494       /* Open logfiles in binary mode so that they reflect
495          exactly what was transmitted and received (that is
496          more important than that they be maximally
497          convenient to view).  */
498       /* Note that if we create several connections in a single CVS client
499          (currently used by update.c), then the last set of logfiles will
500          overwrite the others.  There is currently no way around this.  */
501       strcpy (p, ".in");
502       fp = fopen (buf, "wb");
503       if (!fp)
504         error (0, errno, "opening to-server logfile %s", buf);
505       else
506         *to_server_p = log_buffer_initialize (*to_server_p, fp,
507 # ifdef PROXY_SUPPORT
508                                               false,
509                                               0,
510 # endif /* PROXY_SUPPORT */
511                                               false, NULL);
512
513       strcpy (p, ".out");
514       fp = fopen (buf, "wb");
515       if (!fp)
516         error (0, errno, "opening from-server logfile %s", buf);
517       else
518         *from_server_p = log_buffer_initialize (*from_server_p, fp,
519 # ifdef PROXY_SUPPORT
520                                                 false,
521                                                 0,
522 # endif /* PROXY_SUPPORT */
523                                                 true, NULL);
524
525       free (buf);
526     }
527 }
528
529 #endif /* CLIENT_SUPPORT || SERVER_SUPPORT */