1 /*
2 * Copyright (c) 2008, XenSource Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of XenSource Inc. nor the names of its contributors
13 * may be used to endorse or promote products derived from this software
14 * without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
20 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include <stdio.h>
30 #include <fcntl.h>
31 #include <unistd.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <stdarg.h>
35 #include <syslog.h>
36 #include <inttypes.h>
37 #include <sys/time.h>
38
39 #include "tapdisk-log.h"
40 #include "tapdisk-utils.h"
41
42 #define MAX_ENTRY_LEN 512
43 #define MAX_ERROR_MESSAGES 16
44
45 struct error {
46 int cnt;
47 int err;
48 char *func;
49 char msg[MAX_ENTRY_LEN];
50 };
51
52 struct ehandle {
53 int cnt;
54 int dropped;
55 struct error errors[MAX_ERROR_MESSAGES];
56 };
57
58 struct tlog {
59 char *p;
60 int size;
61 uint64_t cnt;
62 char *buf;
63 int level;
64 char *file;
65 int append;
66 };
67
68 static struct ehandle tapdisk_err;
69 static struct tlog tapdisk_log;
70
71 void
open_tlog(char * file,size_t bytes,int level,int append)72 open_tlog(char *file, size_t bytes, int level, int append)
73 {
74 tapdisk_log.size = ((bytes + 511) & (~511));
75
76 if (asprintf(&tapdisk_log.file, "%s.%d", file, getpid()) == -1)
77 return;
78
79 if (posix_memalign((void **)&tapdisk_log.buf, 512, tapdisk_log.size)) {
80 free(tapdisk_log.file);
81 tapdisk_log.buf = NULL;
82 return;
83 }
84
85 memset(tapdisk_log.buf, 0, tapdisk_log.size);
86
87 tapdisk_log.p = tapdisk_log.buf;
88 tapdisk_log.level = level;
89 tapdisk_log.append = append;
90 }
91
92 void
close_tlog(void)93 close_tlog(void)
94 {
95 if (!tapdisk_log.buf)
96 return;
97
98 if (tapdisk_log.append)
99 tlog_flush();
100
101 free(tapdisk_log.buf);
102 free(tapdisk_log.file);
103
104 memset(&tapdisk_log, 0, sizeof(struct tlog));
105 }
106
107 void
__tlog_write(int level,const char * func,const char * fmt,...)108 __tlog_write(int level, const char *func, const char *fmt, ...)
109 {
110 char *buf;
111 va_list ap;
112 struct timeval t;
113 int ret, len, avail;
114
115 if (!tapdisk_log.buf)
116 return;
117
118 if (level > tapdisk_log.level)
119 return;
120
121 avail = tapdisk_log.size - (tapdisk_log.p - tapdisk_log.buf);
122 if (avail < MAX_ENTRY_LEN) {
123 if (tapdisk_log.append)
124 tlog_flush();
125 tapdisk_log.p = tapdisk_log.buf;
126 }
127
128 buf = tapdisk_log.p;
129 gettimeofday(&t, NULL);
130 len = snprintf(buf, MAX_ENTRY_LEN - 1, "%08"PRIu64":%010ld.%06lld:"
131 "%s ", tapdisk_log.cnt,
132 t.tv_sec, (unsigned long long)t.tv_usec, func);
133
134 va_start(ap, fmt);
135 ret = vsnprintf(buf + len, MAX_ENTRY_LEN - (len + 1), fmt, ap);
136 va_end(ap);
137
138 len = (ret < MAX_ENTRY_LEN - (len + 1) ?
139 len + ret : MAX_ENTRY_LEN - 1);
140 buf[len] = '\0';
141
142 tapdisk_log.cnt++;
143 tapdisk_log.p += len;
144 }
145
146 void
__tlog_error(int err,const char * func,const char * fmt,...)147 __tlog_error(int err, const char *func, const char *fmt, ...)
148 {
149 va_list ap;
150 int i, len, ret;
151 struct error *e;
152 struct timeval t;
153
154 err = (err > 0 ? err : -err);
155
156 for (i = 0; i < tapdisk_err.cnt; i++) {
157 e = &tapdisk_err.errors[i];
158 if (e->err == err && e->func == func) {
159 e->cnt++;
160 return;
161 }
162 }
163
164 if (tapdisk_err.cnt >= MAX_ERROR_MESSAGES) {
165 tapdisk_err.dropped++;
166 return;
167 }
168
169 gettimeofday(&t, NULL);
170 e = &tapdisk_err.errors[tapdisk_err.cnt];
171
172 len = snprintf(e->msg, MAX_ENTRY_LEN - 1, "%010ld.%06lld:%s ",
173 t.tv_sec, (unsigned long long)t.tv_usec, func);
174
175 va_start(ap, fmt);
176 ret = vsnprintf(e->msg + len, MAX_ENTRY_LEN - (len + 1), fmt, ap);
177 va_end(ap);
178
179 len = (ret < MAX_ENTRY_LEN - (len + 1) ?
180 len + ret : MAX_ENTRY_LEN - 1);
181 e->msg[len] = '\0';
182
183 e->cnt++;
184 e->err = err;
185 e->func = (char *)func;
186 tapdisk_err.cnt++;
187 }
188
189 void
tlog_print_errors(void)190 tlog_print_errors(void)
191 {
192 int i;
193 struct error *e;
194
195 for (i = 0; i < tapdisk_err.cnt; i++) {
196 e = &tapdisk_err.errors[i];
197 syslog(LOG_INFO, "TAPDISK ERROR: errno %d at %s (cnt = %d): "
198 "%s\n", e->err, e->func, e->cnt, e->msg);
199 }
200
201 if (tapdisk_err.dropped)
202 syslog(LOG_INFO, "TAPDISK ERROR: %d other error messages "
203 "dropped\n", tapdisk_err.dropped);
204 }
205
206 void
tlog_flush_errors(void)207 tlog_flush_errors(void)
208 {
209 int i;
210 struct error *e;
211
212 for (i = 0; i < tapdisk_err.cnt; i++) {
213 e = &tapdisk_err.errors[i];
214 tlog_write(TLOG_WARN, "TAPDISK ERROR: errno %d at %s "
215 "(cnt = %d): %s\n", e->err, e->func, e->cnt,
216 e->msg);
217 }
218
219 if (tapdisk_err.dropped)
220 tlog_write(TLOG_WARN, "TAPDISK ERROR: %d other error messages "
221 "dropped\n", tapdisk_err.dropped);
222 }
223
224 void
tlog_flush(void)225 tlog_flush(void)
226 {
227 int fd, flags;
228 size_t size, wsize;
229
230 if (!tapdisk_log.buf)
231 return;
232
233 flags = O_CREAT | O_WRONLY | O_DIRECT | O_NONBLOCK;
234 if (!tapdisk_log.append)
235 flags |= O_TRUNC;
236
237 fd = open(tapdisk_log.file, flags, 0644);
238 if (fd == -1)
239 return;
240
241 if (tapdisk_log.append)
242 if (lseek(fd, 0, SEEK_END) == (off_t)-1)
243 goto out;
244
245 tlog_flush_errors();
246
247 size = tapdisk_log.p - tapdisk_log.buf;
248 wsize = ((size + 511) & (~511));
249
250 memset(tapdisk_log.buf + size, '\n', wsize - size);
251 write_exact(fd, tapdisk_log.buf, wsize);
252
253 tapdisk_log.p = tapdisk_log.buf;
254
255 out:
256 close(fd);
257 }
258