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 */ 530