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