/* The input function for a log buffer. */ static int ms_buffer_input (void *closure, char *data, size_t need, size_t size, size_t *got) { struct ms_buffer *mb = closure; int status; assert (mb->cur->input); status = (*mb->cur->input) (mb->cur->closure, data, need, size, got); if (status == -1) { Node *p; /* EOF. Set up the next buffer in line but return success and no * data since our caller may have selected on the target to find * ready data before calling us. * * If there are no more buffers, return EOF. */ if (list_isempty (mb->bufs)) return -1; buf_shutdown (mb->cur); buf_free (mb->cur); p = mb->bufs->list->next; mb->cur = p->data; p->delproc = NULL; p->data = NULL; delnode (p); if (!buf_empty_p (mb->cur)) buf_append_buffer (mb->buf, mb->cur); ms_buffer_block (closure, mb->block); *got = 0; status = 0; } return status; }
/* Disable logging without shutting down the next buffer in the chain. */ struct buffer * log_buffer_rewind (struct buffer *buf) { struct log_buffer *lb = buf->closure; struct buffer *retbuf; int fd; lb->disabled = true; if (lb->log) { FILE *tmp = lb->log; lb->log = NULL; /* flush & rewind the file. */ if (fflush (tmp) < 0) error (0, errno, "flushing log file"); rewind (tmp); /* Get a descriptor for the log and close the FILE *. */ fd = dup (fileno (tmp)); if (fclose (tmp) < 0) error (0, errno, "closing log file"); } else fd = open (DEVNULL, O_RDONLY); /* Catch dup/open errors. */ if (fd < 0) { error (lb->fatal_errors, errno, "failed to rewind log buf."); return NULL; } /* Create a new fd buffer around the log. */ retbuf = fd_buffer_initialize (fd, 0, NULL, true, buf->memory_error); { struct buffer *tmp; /* Insert the data which wasn't written to a file. */ buf_append_buffer (retbuf, lb->back_buf); tmp = lb->back_buf; lb->back_buf = NULL; buf_free (tmp); } return retbuf; }
/* Create a multi-source buffer. This could easily be generalized to support * any number of source buffers, but for now only two are necessary. */ struct buffer * ms_buffer_initialize (void (*memory) (struct buffer *), struct buffer *buf, struct buffer *buf2/*, ...*/) { struct ms_buffer *mb = xmalloc (sizeof *mb); struct buffer *retbuf; Node *p; mb->block = false; mb->cur = buf; set_nonblock (buf); mb->bufs = getlist (); p = getnode (); p->data = buf2; p->delproc = delbuflist; addnode (mb->bufs, p); retbuf = buf_initialize (ms_buffer_input, NULL, NULL, ms_buffer_block, ms_buffer_get_fd, ms_buffer_shutdown, memory, mb); if (!buf_empty_p (buf)) buf_append_buffer (retbuf, buf); mb->buf = retbuf; return retbuf; }
struct buffer * log_buffer_initialize (struct buffer *buf, FILE *fp, # ifdef PROXY_SUPPORT bool fatal_errors, size_t max, # endif /* PROXY_SUPPORT */ bool input, void (*memory) (struct buffer *)) { struct log_buffer *lb = xmalloc (sizeof *lb); struct buffer *retbuf; lb->buf = buf; lb->log = fp; #ifdef PROXY_SUPPORT lb->back_fn = NULL; lb->fatal_errors = fatal_errors; lb->disabled = false; assert (size_in_bounds_p (max)); lb->max = max; lb->tofile = false; lb->back_buf = buf_nonio_initialize (memory); #endif /* PROXY_SUPPORT */ retbuf = buf_initialize (input ? log_buffer_input : NULL, input ? NULL : log_buffer_output, input ? NULL : log_buffer_flush, log_buffer_block, log_buffer_get_fd, log_buffer_shutdown, memory, lb); if (!buf_empty_p (buf)) { /* If our buffer already had data, copy it & log it if necessary. This * can happen, for instance, with a pserver, where we deliberately do * not instantiate the log buffer until after authentication so that * auth data does not get logged (the pserver data will not be logged * in this case, but any data which was left unused in the buffer by * the auth code will be logged and put in our new buffer). */ struct buffer_data *data; #ifdef PROXY_SUPPORT size_t total = 0; #endif /* PROXY_SUPPORT */ for (data = buf->data; data != NULL; data = data->next) { #ifdef PROXY_SUPPORT if (!lb->tofile) { total = xsum (data->size, total); if (total >= max) lb->tofile = true; } if (lb->tofile) { if (!lb->log) log_buffer_force_file (lb); if (lb->log) { #endif /* PROXY_SUPPORT */ if (fwrite (data->bufp, 1, data->size, lb->log) != (size_t) data->size) error ( #ifdef PROXY_SUPPORT fatal_errors, #else /* !PROXY_SUPPORT */ false, #endif /* PROXY_SUPPORT */ errno, "writing to log file"); fflush (lb->log); #ifdef PROXY_SUPPORT } } else /* Log to memory buffer. */ buf_copy_data (lb->back_buf, data, data); #endif /* PROXY_SUPPORT */ } buf_append_buffer (retbuf, buf); } return retbuf; }