kernel: Remove the FFS_ROOT option. It was a no-op since 4.9.
[dragonfly.git] / contrib / cvs-1.12 / src / log-buffer.c
blobc7cb6a965058e60dde28f5163cf2282a85ef45f5
1 /* CVS client logging buffer.
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.
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. */
13 #include <config.h>
15 #include <stdio.h>
17 #include "cvs.h"
18 #include "buffer.h"
20 #if defined CLIENT_SUPPORT || defined SERVER_SUPPORT
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.
26 This structure is the closure field of a log buffer. */
28 struct log_buffer
30 /* The underlying buffer. */
31 struct buffer *buf;
32 /* The file to log information to. */
33 FILE *log;
35 #ifdef PROXY_SUPPORT
36 /* Whether errors writing to the log file should be fatal or not. */
37 bool fatal_errors;
39 /* The name of the file backing this buffer so that it may be deleted on
40 * buffer shutdown.
42 char *back_fn;
44 /* Set once logging is permanently disabled for a buffer. */
45 bool disabled;
47 /* The memory buffer (cache) backing this log. */
48 struct buffer *back_buf;
50 /* The maximum number of bytes to store in memory before beginning logging
51 * to a file.
53 size_t max;
55 /* Once we start logging to a file we do not want to stop unless asked. */
56 bool tofile;
57 #endif /* PROXY_SUPPORT */
62 #ifdef PROXY_SUPPORT
63 /* Force the existance of lb->log.
65 * INPUTS
66 * lb The log buffer.
68 * OUTPUTS
69 * lb->log The new FILE *.
70 * lb->back_fn The name of the new log, for later disposal.
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..
76 * RETURNS
77 * Nothing.
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.
83 static inline void
84 log_buffer_force_file (struct log_buffer *lb)
86 lb->log = cvs_temp_file (&lb->back_fn);
87 if (!lb->log)
88 error (lb->fatal_errors, errno, "failed to open log file.");
90 #endif /* PROXY_SUPPORT */
94 /* Create a log buffer.
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.
115 * RETURNS
116 * A pointer to a new buffer structure.
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 *))
133 struct log_buffer *lb = xmalloc (sizeof *lb);
134 struct buffer *retbuf;
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);
153 if (!buf_empty_p (buf))
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).
162 struct buffer_data *data;
163 #ifdef PROXY_SUPPORT
164 size_t total = 0;
165 #endif /* PROXY_SUPPORT */
167 for (data = buf->data; data != NULL; data = data->next)
169 #ifdef PROXY_SUPPORT
170 if (!lb->tofile)
172 total = xsum (data->size, total);
173 if (total >= max)
174 lb->tofile = true;
177 if (lb->tofile)
179 if (!lb->log) log_buffer_force_file (lb);
180 if (lb->log)
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
196 else
197 /* Log to memory buffer. */
198 buf_copy_data (lb->back_buf, data, data);
199 #endif /* PROXY_SUPPORT */
201 buf_append_buffer (retbuf, buf);
203 return retbuf;
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)
213 struct log_buffer *lb = closure;
214 int status;
216 assert (lb->buf->input);
218 status = (*lb->buf->input) (lb->buf->closure, data, need, size, got);
219 if (status != 0)
220 return status;
222 if (
223 #ifdef PROXY_SUPPORT
224 !lb->disabled &&
225 #endif /* PROXY_SUPPORT */
226 *got > 0)
228 #ifdef PROXY_SUPPORT
229 if (!lb->tofile
230 && xsum (*got, buf_count_mem (lb->back_buf)) >= lb->max)
231 lb->tofile = true;
233 if (lb->tofile)
235 if (!lb->log) log_buffer_force_file (lb);
236 if (lb->log)
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
251 else
252 /* Log to memory buffer. */
253 buf_output (lb->back_buf, data, *got);
254 #endif /* PROXY_SUPPORT */
257 return 0;
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)
266 struct log_buffer *lb = closure;
267 int status;
269 assert (lb->buf->output);
271 status = (*lb->buf->output) (lb->buf->closure, data, have, wrote);
272 if (status != 0)
273 return status;
275 if (
276 #ifdef PROXY_SUPPORT
277 !lb->disabled &&
278 #endif /* PROXY_SUPPORT */
279 *wrote > 0)
281 #ifdef PROXY_SUPPORT
282 if (!lb->tofile
283 && xsum (*wrote, buf_count_mem (lb->back_buf)) >= lb->max)
284 lb->tofile = true;
286 if (lb->tofile)
288 if (!lb->log) log_buffer_force_file (lb);
289 if (lb->log)
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
304 else
305 /* Log to memory buffer. */
306 buf_output (lb->back_buf, data, *wrote);
307 #endif /* PROXY_SUPPORT */
310 return 0;
315 /* The flush function for a log buffer. */
316 static int
317 log_buffer_flush (void *closure)
319 struct log_buffer *lb = closure;
321 assert (lb->buf->flush);
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.
327 if (lb->log && (fflush (lb->log)))
328 error (0, errno, "flushing log file");
330 return (*lb->buf->flush) (lb->buf->closure);
335 /* The block function for a log buffer. */
336 static int
337 log_buffer_block (void *closure, bool block)
339 struct log_buffer *lb = closure;
341 if (block)
342 return set_block (lb->buf);
343 else
344 return set_nonblock (lb->buf);
349 #ifdef PROXY_SUPPORT
350 /* Disable logging without shutting down the next buffer in the chain.
352 struct buffer *
353 log_buffer_rewind (struct buffer *buf)
355 struct log_buffer *lb = buf->closure;
356 struct buffer *retbuf;
357 int fd;
359 lb->disabled = true;
361 if (lb->log)
363 FILE *tmp = lb->log;
364 lb->log = NULL;
366 /* flush & rewind the file. */
367 if (fflush (tmp) < 0)
368 error (0, errno, "flushing log file");
369 rewind (tmp);
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");
376 else
377 fd = open (DEVNULL, O_RDONLY);
379 /* Catch dup/open errors. */
380 if (fd < 0)
382 error (lb->fatal_errors, errno, "failed to rewind log buf.");
383 return NULL;
386 /* Create a new fd buffer around the log. */
387 retbuf = fd_buffer_initialize (fd, 0, NULL, true, buf->memory_error);
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);
398 return retbuf;
400 #endif /* PROXY_SUPPORT */
404 /* Disable logging and close the log without shutting down the next buffer in
405 * the chain.
407 #ifndef PROXY_SUPPORT
408 static
409 #endif /* !PROXY_SUPPORT */
410 void
411 log_buffer_closelog (struct buffer *buf)
413 struct log_buffer *lb = buf->closure;
414 void *tmp;
416 #ifdef PROXY_SUPPORT
417 lb->disabled = true;
418 #endif /* PROXY_SUPPORT */
420 /* Close the log. */
421 if (lb->log)
423 tmp = lb->log;
424 lb->log = NULL;
425 if (fclose (tmp) < 0)
426 error (0, errno, "closing log file");
429 #ifdef PROXY_SUPPORT
430 /* Delete the log if we know its name. */
431 if (lb->back_fn)
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);
440 if (lb->back_buf)
442 tmp = lb->back_buf;
443 lb->back_buf = NULL;
444 buf_free (tmp);
446 #endif /* PROXY_SUPPORT */
451 /* Return the file descriptor underlying any child buffers. */
452 static int
453 log_buffer_get_fd (void *closure)
455 struct log_buffer *lb = closure;
456 return buf_get_fd (lb->buf);
461 /* The shutdown function for a log buffer. */
462 static int
463 log_buffer_shutdown (struct buffer *buf)
465 struct log_buffer *lb = buf->closure;
467 log_buffer_closelog (buf);
468 return buf_shutdown (lb->buf);
473 void
474 setup_logfiles (char *var, struct buffer **to_server_p,
475 struct buffer **from_server_p)
477 char *log = getenv (var);
479 /* Set up logfiles, if any.
481 * We do this _after_ authentication on purpose. Wouldn't really like to
482 * worry about logging passwords...
484 if (log)
486 int len = strlen (log);
487 char *buf = xmalloc (len + 5);
488 char *p;
489 FILE *fp;
491 strcpy (buf, log);
492 p = buf + len;
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,
510 # endif /* PROXY_SUPPORT */
511 false, NULL);
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,
522 # endif /* PROXY_SUPPORT */
523 true, NULL);
525 free (buf);
529 #endif /* CLIENT_SUPPORT || SERVER_SUPPORT */