Home | History | Annotate | Download | only in common
      1 /* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
      2  * Use of this source code is governed by a BSD-style license that can be
      3  * found in the LICENSE file.
      4  */
      5 
      6 #include <stdarg.h>
      7 #include <stdlib.h>
      8 #include <string.h>
      9 #include <syslog.h>
     10 
     11 #include "dumper.h"
     12 
     13 void dumpf(struct dumper *dumper, const char *format, ...)
     14 {
     15 	va_list ap;
     16 	va_start(ap, format);
     17 	dumper->vprintf(dumper, format, ap);
     18 	va_end(ap);
     19 }
     20 
     21 /* dumper which outputs to syslog */
     22 
     23 struct syslog_data {
     24 	int priority;
     25 	struct dumper *mem_dumper;
     26 };
     27 
     28 static void syslog_vprintf(struct dumper *dumper, const char *fmt, va_list ap)
     29 {
     30 	char *buf;
     31 	int size, i;
     32 	struct syslog_data *data = (struct syslog_data *)dumper->data;
     33 	struct dumper *mem_dumper = data->mem_dumper;
     34 
     35 	/* We cannot use syslog() directly each time we are called,
     36 	 * because syslog() will always append a newline to the
     37 	 * output, so the user will not be able to construct a line
     38 	 * incrementally using multiple calls. What we do here is to
     39 	 * collect the output in a buffer until a newline is given by
     40 	 * the user. */
     41 
     42 	mem_dumper->vprintf(mem_dumper, fmt, ap);
     43 again:
     44 	mem_dumper_get(mem_dumper, &buf, &size);
     45 	for (i = 0; i < size; i++) {
     46 		if (buf[i] == '\n') {
     47 			syslog(data->priority, "%.*s", i + 1, buf);
     48 			mem_dumper_consume(mem_dumper, i + 1);
     49 			goto again;
     50 		}
     51 	}
     52 }
     53 
     54 struct dumper *syslog_dumper_create(int priority)
     55 {
     56 	struct dumper *dumper = calloc(1, sizeof(struct dumper));
     57 	struct syslog_data *data = calloc(1, sizeof(struct syslog_data));
     58 	data->priority = priority;
     59 	data->mem_dumper = mem_dumper_create();
     60 	dumper->data = data;
     61 	dumper->vprintf = &syslog_vprintf;
     62 	return dumper;
     63 }
     64 
     65 void syslog_dumper_free(struct dumper *dumper)
     66 {
     67 	mem_dumper_free(((struct syslog_data *)dumper->data)->mem_dumper);
     68 	free(dumper->data);
     69 	free(dumper);
     70 }
     71 
     72 /* dumper which outputs to a memory buffer */
     73 
     74 struct mem_data {
     75 	char *buf;
     76 	int size;
     77 	int capacity;
     78 };
     79 
     80 static void mem_vprintf(struct dumper *dumper, const char *format, va_list ap)
     81 {
     82 	int n;
     83 	char *tmp;
     84 	struct mem_data *data = (struct mem_data *)dumper->data;
     85 
     86 	while (1) {
     87 		/* try to use the remaining space */
     88 		int remaining = data->capacity - data->size;
     89 		n = vsnprintf(data->buf + data->size, remaining, format, ap);
     90 
     91 		/* enough space? */
     92 		if (n > -1 && n < remaining) {
     93 			data->size += n;
     94 			return;
     95 		}
     96 
     97 		/* allocate more space and try again */
     98 		tmp = realloc(data->buf, data->capacity * 2);
     99 		if (tmp == NULL)
    100 			return;
    101 		data->buf = tmp;
    102 		data->capacity *= 2;
    103 	}
    104 }
    105 
    106 struct dumper *mem_dumper_create()
    107 {
    108 	struct dumper *dumper = calloc(1, sizeof(struct dumper));
    109 	struct mem_data *data = calloc(1, sizeof(struct mem_data));
    110 	if (!dumper || !data)
    111 		return NULL;
    112 	data->size = 0;
    113 	data->capacity = 80;
    114 	data->buf = malloc(data->capacity);
    115 	if (!data->buf) {
    116 		free(data);
    117 		return NULL;
    118 	}
    119 	data->buf[0] = '\0';
    120 	dumper->data = data;
    121 	dumper->vprintf = &mem_vprintf;
    122 	return dumper;
    123 }
    124 
    125 void mem_dumper_free(struct dumper *dumper)
    126 {
    127 	struct mem_data *data = (struct mem_data *)dumper->data;
    128 	free(data->buf);
    129 	free(data);
    130 	free(dumper);
    131 }
    132 
    133 void mem_dumper_clear(struct dumper *dumper)
    134 {
    135 	struct mem_data *data = (struct mem_data *)dumper->data;
    136 	data->buf[0] = '\0';
    137 	data->size = 0;
    138 }
    139 
    140 void mem_dumper_consume(struct dumper *dumper, int n)
    141 {
    142 	struct mem_data *data = (struct mem_data *)dumper->data;
    143 	if (n > data->size)
    144 		n = data->size;
    145 	memmove(data->buf, data->buf + n, data->size - n + 1);
    146 	data->size -= n;
    147 }
    148 
    149 void mem_dumper_get(struct dumper *dumper, char **buf, int *size)
    150 {
    151 	struct mem_data *data = (struct mem_data *)dumper->data;
    152 	*buf = data->buf;
    153 	*size = data->size;
    154 }
    155