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