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