static int zio_fd_read (zio_t *zio, void *dst, int len) { assert (zio != NULL); assert (zio->magic == ZIO_MAGIC); assert (zio->buf); if (zio_line_buffered (zio) && !zio_eof (zio)) return cbuf_read_line (zio->buf, dst, len, -1); else return cbuf_read (zio->buf, dst, len); }
static int _pstdout_print(pstdout_state_t pstate, int internal_to_pstdout, FILE *stream, const char *format, va_list ap) { char *buf = NULL; char *linebuf = NULL; size_t buflen = PSTDOUT_BUFLEN; size_t linebuflen = PSTDOUT_BUFLEN; cbuf_t whichcbuf; uint32_t whichdefaultmask; uint32_t whichprependmask; uint32_t whichbuffermask; uint32_t whichconsolidatemask; char **whichbuffer; unsigned int *whichbufferlen; int wlen; int linelen; int pstate_mutex_locked = 0; int rc, rv = -1; assert(pstate); assert(pstate->magic == PSTDOUT_STATE_MAGIC); assert(pstate->p_stdout); assert(pstate->p_stderr); assert(stream); assert(stream == stdout || stream == stderr); assert(format); assert(ap); if (stream == stdout) { whichcbuf = pstate->p_stdout; whichdefaultmask = PSTDOUT_OUTPUT_STDOUT_DEFAULT; whichprependmask = PSTDOUT_OUTPUT_STDOUT_PREPEND_HOSTNAME; whichbuffermask = PSTDOUT_OUTPUT_BUFFER_STDOUT; whichconsolidatemask = PSTDOUT_OUTPUT_STDOUT_CONSOLIDATE; whichbuffer = &(pstate->buffer_stdout); whichbufferlen = &(pstate->buffer_stdout_len); } else { whichcbuf = pstate->p_stderr; whichdefaultmask = PSTDOUT_OUTPUT_STDERR_DEFAULT; whichprependmask = PSTDOUT_OUTPUT_STDERR_PREPEND_HOSTNAME; whichbuffermask = PSTDOUT_OUTPUT_BUFFER_STDERR; whichconsolidatemask = PSTDOUT_OUTPUT_STDERR_CONSOLIDATE; whichbuffer = &(pstate->buffer_stderr); whichbufferlen = &(pstate->buffer_stderr_len); } while (1) { va_list vacpy; if (!(buf = (char *)realloc(buf, buflen))) { pstdout_errnum = PSTDOUT_ERR_OUTMEM; goto cleanup; } memset(buf, '\0', PSTDOUT_BUFLEN); va_copy(vacpy, ap); wlen = vsnprintf(buf, buflen, format, vacpy); va_end(vacpy); if (wlen < buflen) break; buflen += PSTDOUT_BUFLEN; } if ((rc = pthread_mutex_lock(&(pstate->mutex)))) { if (pstdout_debug_flags & PSTDOUT_DEBUG_STANDARD) fprintf(stderr, "pthread_mutex_lock: %s\n", strerror(rc)); pstdout_errnum = PSTDOUT_ERR_INTERNAL; goto cleanup; } pstate_mutex_locked++; /* Protect from racing output when we are in a Ctrl+C flushing * buffered output situation */ if (!internal_to_pstdout && pstate->no_more_external_output) goto cleanup; if (cbuf_write(whichcbuf, buf, wlen, NULL) < 0) { if (pstdout_debug_flags & PSTDOUT_DEBUG_STANDARD) fprintf(stderr, "cbuf_write: %s\n", strerror(errno)); pstdout_errnum = PSTDOUT_ERR_INTERNAL; goto cleanup; } while (1) { if (!(linebuf = (char *)realloc(linebuf, linebuflen))) { pstdout_errnum = PSTDOUT_ERR_OUTMEM; goto cleanup; } memset(linebuf, '\0', PSTDOUT_BUFLEN); while ((linelen = cbuf_read_line (whichcbuf, linebuf, linebuflen, 1)) > 0) { if (linelen >= linebuflen) break; if (!pstate->hostname || ((pstdout_output_flags & whichdefaultmask) && !(pstdout_output_flags & whichbuffermask) && !(pstdout_output_flags & whichconsolidatemask))) { rv = fprintf(stream, "%s", linebuf); fflush(stream); } else if (pstdout_output_flags & whichprependmask && !(pstdout_output_flags & whichbuffermask) && !(pstdout_output_flags & whichconsolidatemask)) { rv = fprintf(stream, "%s: %s", pstate->hostname, linebuf); fflush(stream); } else if (((pstdout_output_flags & whichdefaultmask) && (pstdout_output_flags & whichbuffermask)) || (pstdout_output_flags & whichconsolidatemask)) { if (!(*whichbuffer = (char *)realloc(*whichbuffer, *whichbufferlen + linelen))) { pstdout_errnum = PSTDOUT_ERR_OUTMEM; goto cleanup; } /* Don't use snprintf, it will truncate b/c "snprintf and vsnprintf do not write more than size bytes (including the trailing '\0'). " */ memcpy(*whichbuffer + *whichbufferlen, linebuf, linelen); *whichbufferlen += linelen; rv = linelen; } else if ((pstdout_output_flags & whichprependmask) && (pstdout_output_flags & whichbuffermask)) { unsigned int hostname_len; unsigned int extra_len; /* + 2 is for the ": " */ hostname_len = strlen(pstate->hostname); extra_len = hostname_len + 2; if (!(*whichbuffer = (char *)realloc(*whichbuffer, *whichbufferlen + linelen + extra_len))) { pstdout_errnum = PSTDOUT_ERR_OUTMEM; goto cleanup; } /* Don't use snprintf, it will truncate b/c "snprintf and vsnprintf do not write more than size bytes (including the trailing '\0'). " */ memcpy(*whichbuffer + *whichbufferlen, pstate->hostname, hostname_len); memcpy(*whichbuffer + *whichbufferlen + hostname_len, ": ", 2); memcpy(*whichbuffer + *whichbufferlen + hostname_len + 2, linebuf, linelen); *whichbufferlen += linelen + extra_len; rv = linelen + extra_len; } else { pstdout_errnum = PSTDOUT_ERR_INTERNAL; return -1; } } if (linelen < 0) { if (pstdout_debug_flags & PSTDOUT_DEBUG_STANDARD) fprintf(stderr, "cbuf_read_line: %s\n", strerror(errno)); pstdout_errnum = PSTDOUT_ERR_INTERNAL; goto cleanup; } if (!linelen) break; linebuflen += PSTDOUT_BUFLEN; } if (rv < 0) rv = 0; pstdout_errnum = PSTDOUT_ERR_SUCCESS; cleanup: if (pstate_mutex_locked) { if ((rc = pthread_mutex_unlock(&(pstate->mutex)))) { if (pstdout_debug_flags & PSTDOUT_DEBUG_STANDARD) fprintf(stderr, "pthread_mutex_unlock: %s\n", strerror(rc)); /* Don't change error code, just move on */ } } free(buf); free(linebuf); return rv; }