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