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
dumpf(struct dumper * dumper,const char * format,...)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
syslog_vprintf(struct dumper * dumper,const char * fmt,va_list ap)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
syslog_dumper_create(int priority)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
syslog_dumper_free(struct dumper * dumper)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
mem_vprintf(struct dumper * dumper,const char * format,va_list ap)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
mem_dumper_create()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
mem_dumper_free(struct dumper * dumper)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
mem_dumper_clear(struct dumper * dumper)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
mem_dumper_consume(struct dumper * dumper,int n)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
mem_dumper_get(struct dumper * dumper,char ** buf,int * size)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