Update Red Hat Copyright Notices
[nbdkit.git] / filters / log / log.c
blob5e3ba099120e4b04cceff55de1179610330e0bc1
1 /* nbdkit
2 * Copyright Red Hat
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * * Neither the name of Red Hat nor the names of its contributors may be
16 * used to endorse or promote products derived from this software without
17 * specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
22 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
29 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
33 #include <config.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <stdint.h>
38 #include <stdbool.h>
39 #include <string.h>
40 #include <stdarg.h>
41 #include <errno.h>
42 #include <inttypes.h>
43 #include <pthread.h>
44 #include <assert.h>
45 #include <fcntl.h>
46 #include <unistd.h>
47 #include <sys/types.h>
49 #include <nbdkit-filter.h>
51 #include "cleanup.h"
52 #include "utils.h"
53 #include "windows-compat.h"
55 #include "log.h"
57 /* We use the equivalent of printf ("") several times in this file
58 * which worries GCC. Ignore these.
60 #pragma GCC diagnostic ignored "-Wformat-zero-length"
62 uint64_t connections;
63 const char *logfilename;
64 FILE *logfile;
65 const char *logscript;
66 int append;
67 pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
68 pid_t saved_pid;
70 static void
71 log_unload (void)
73 if (logfile)
74 fclose (logfile);
77 /* Called for each key=value passed on the command line. */
78 static int
79 log_config (nbdkit_next_config *next, nbdkit_backend *nxdata,
80 const char *key, const char *value)
82 if (strcmp (key, "logfile") == 0) {
83 logfilename = value;
84 return 0;
86 if (strcmp (key, "logappend") == 0) {
87 append = nbdkit_parse_bool (value);
88 if (append < 0)
89 return -1;
90 return 0;
92 if (strcmp (key, "logscript") == 0) {
93 logscript = value;
94 return 0;
96 return next (nxdata, key, value);
99 #define log_config_help \
100 "logfile=<FILE> The file to place the log in.\n" \
101 "logappend=<BOOL> True to append to the log (default false).\n" \
102 "logscript=<SCRIPT> Script to run for logging."
104 /* Open the logfile. */
105 static int
106 log_get_ready (int thread_model)
108 int fd;
110 if (logfilename) {
111 /* Using fopen("ae"/"we") would be more convenient, but as Haiku
112 * still lacks that, use this instead. Atomicity is not essential
113 * here since .config completes before threads that might fork, if
114 * we have to later add yet another fallback to fcntl(fileno()) for
115 * systems without O_CLOEXEC.
117 fd = open (logfilename,
118 O_CLOEXEC | O_WRONLY | O_CREAT | (append ? O_APPEND : O_TRUNC),
119 0666);
120 if (fd < 0) {
121 nbdkit_error ("open: %s: %m", logfilename);
122 return -1;
124 logfile = fdopen (fd, append ? "a" : "w");
125 if (!logfile) {
126 nbdkit_error ("fdopen: %s: %m", logfilename);
127 close (fd);
128 return -1;
132 saved_pid = getpid ();
134 print (NULL, "Ready", "thread_model=%d", thread_model);
135 return 0;
138 static int
139 log_after_fork (nbdkit_backend *nxdata)
141 /* Only issue this message if we actually fork. */
142 if (getpid () != saved_pid)
143 print (NULL, "Fork", "");
145 return 0;
148 /* List exports. */
149 static int
150 log_list_exports (nbdkit_next_list_exports *next, nbdkit_backend *nxdata,
151 int readonly, int is_tls,
152 struct nbdkit_exports *exports)
154 static log_id_t id;
155 int r;
156 int err;
158 enter (NULL, ++id, "ListExports", "readonly=%d tls=%d", readonly, is_tls);
159 r = next (nxdata, readonly, exports);
160 if (r == -1) {
161 err = errno;
162 leave_simple (NULL, id, "ListExports", r, &err);
164 else {
165 FILE *fp;
166 CLEANUP_FREE char *str = NULL;
167 size_t i, n, len = 0;
169 fp = open_memstream (&str, &len);
170 if (fp != NULL) {
171 fprintf (fp, "exports=(");
172 n = nbdkit_exports_count (exports);
173 for (i = 0; i < n; ++i) {
174 struct nbdkit_export e = nbdkit_get_export (exports, i);
175 if (i > 0)
176 fprintf (fp, " ");
177 shell_quote (e.name, fp);
179 fprintf (fp, ") return=0");
180 fclose (fp);
181 leave (NULL, id, "ListExports", "%s", str);
183 else
184 leave (NULL, id, "ListExports", "");
186 return r;
189 static int
190 log_preconnect (nbdkit_next_preconnect *next, nbdkit_backend *nxdata,
191 int readonly)
193 static log_id_t id;
194 int r;
195 int err;
197 enter (NULL, ++id, "Preconnect", "readonly=%d", readonly);
198 r = next (nxdata, readonly);
199 if (r == -1)
200 err = errno;
201 leave_simple (NULL, id, "Preconnect", r, &err);
202 return r;
205 /* Open a connection. */
206 static void *
207 log_open (nbdkit_next_open *next, nbdkit_context *nxdata,
208 int readonly, const char *exportname, int is_tls)
210 struct handle *h;
212 if (next (nxdata, readonly, exportname) == -1)
213 return NULL;
215 h = malloc (sizeof *h);
216 if (h == NULL) {
217 nbdkit_error ("malloc: %m");
218 return NULL;
221 /* Save the exportname and tls state in the handle so we can display
222 * it in log_prepare. We must take a copy because this string has a
223 * short lifetime.
225 h->exportname = nbdkit_strdup_intern (exportname);
226 if (h->exportname == NULL) {
227 free (h);
228 return NULL;
230 h->tls = is_tls;
232 ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&lock);
233 h->connection = ++connections;
234 h->id = 0;
235 return h;
238 static void
239 log_close (void *handle)
241 free (handle);
244 static int
245 log_prepare (nbdkit_next *next, void *handle,
246 int readonly)
248 FILE *fp;
249 CLEANUP_FREE char *str = NULL;
250 size_t len = 0;
251 struct handle *h = handle;
252 const char *exportname = h->exportname;
253 int64_t size = next->get_size (next);
254 uint32_t minsize, prefsize, maxsize;
255 int w = next->can_write (next);
256 int f = next->can_flush (next);
257 int r = next->is_rotational (next);
258 int t = next->can_trim (next);
259 int z = next->can_zero (next);
260 int F = next->can_fua (next);
261 int e = next->can_extents (next);
262 int c = next->can_cache (next);
263 int Z = next->can_fast_zero (next);
264 int s = next->block_size (next, &minsize, &prefsize, &maxsize);
266 if (size < 0 || w < 0 || f < 0 || r < 0 || t < 0 || z < 0 || F < 0 ||
267 e < 0 || c < 0 || Z < 0 || s < 0)
268 return -1;
270 fp = open_memstream (&str, &len);
271 if (fp) {
272 fprintf (fp, "export=");
273 shell_quote (exportname, fp);
274 fprintf (fp,
275 " tls=%d size=0x%" PRIx64 " minsize=0x%" PRIx32 " prefsize=0x%"
276 PRIx32 " maxsize=0x%" PRIx32 " write=%d "
277 "flush=%d rotational=%d trim=%d zero=%d fua=%d extents=%d "
278 "cache=%d fast_zero=%d",
279 h->tls, size, minsize, prefsize, maxsize,
280 w, f, r, t, z, F, e, c, Z);
281 fclose (fp);
282 print (h, "Connect", "%s", str);
284 else
285 print (h, "Connect", "");
287 return 0;
290 static int
291 log_finalize (nbdkit_next *next, void *handle)
293 struct handle *h = handle;
295 print (h, "Disconnect", "transactions=%" PRId64, h->id);
296 return 0;
299 /* Read data. */
300 static int
301 log_pread (nbdkit_next *next,
302 void *handle, void *buf, uint32_t count, uint64_t offs,
303 uint32_t flags, int *err)
305 struct handle *h = handle;
306 int r;
308 LOG (h, "Read", r, err, "offset=0x%" PRIx64 " count=0x%x", offs, count);
310 assert (!flags);
311 return r = next->pread (next, buf, count, offs, flags, err);
314 /* Write data. */
315 static int
316 log_pwrite (nbdkit_next *next,
317 void *handle, const void *buf, uint32_t count, uint64_t offs,
318 uint32_t flags, int *err)
320 struct handle *h = handle;
321 int r;
323 LOG (h, "Write", r, err,
324 "offset=0x%" PRIx64 " count=0x%x fua=%d",
325 offs, count, !!(flags & NBDKIT_FLAG_FUA));
327 assert (!(flags & ~NBDKIT_FLAG_FUA));
328 return r = next->pwrite (next, buf, count, offs, flags, err);
331 /* Flush. */
332 static int
333 log_flush (nbdkit_next *next, void *handle,
334 uint32_t flags, int *err)
336 struct handle *h = handle;
337 int r;
339 LOG (h, "Flush", r, err, "");
341 assert (!flags);
342 return r = next->flush (next, flags, err);
345 /* Trim data. */
346 static int
347 log_trim (nbdkit_next *next,
348 void *handle, uint32_t count, uint64_t offs, uint32_t flags,
349 int *err)
351 struct handle *h = handle;
352 int r;
354 LOG (h, "Trim", r, err,
355 "offset=0x%" PRIx64 " count=0x%x fua=%d",
356 offs, count, !!(flags & NBDKIT_FLAG_FUA));
358 assert (!(flags & ~NBDKIT_FLAG_FUA));
359 return r = next->trim (next, count, offs, flags, err);
362 /* Zero data. */
363 static int
364 log_zero (nbdkit_next *next,
365 void *handle, uint32_t count, uint64_t offs, uint32_t flags,
366 int *err)
368 struct handle *h = handle;
369 int r;
371 LOG (h, "Zero", r, err,
372 "offset=0x%" PRIx64 " count=0x%x trim=%d fua=%d fast=%d",
373 offs, count, !!(flags & NBDKIT_FLAG_MAY_TRIM),
374 !!(flags & NBDKIT_FLAG_FUA),
375 !!(flags & NBDKIT_FLAG_FAST_ZERO));
377 assert (!(flags & ~(NBDKIT_FLAG_FUA | NBDKIT_FLAG_MAY_TRIM |
378 NBDKIT_FLAG_FAST_ZERO)));
379 return r = next->zero (next, count, offs, flags, err);
382 /* Extents. */
383 static int
384 log_extents (nbdkit_next *next,
385 void *handle, uint32_t count, uint64_t offs, uint32_t flags,
386 struct nbdkit_extents *extents, int *err)
388 struct handle *h = handle;
389 log_id_t id = get_id (h);
390 int r;
392 assert (!(flags & ~(NBDKIT_FLAG_REQ_ONE)));
393 enter (h, id, "Extents",
394 "offset=0x%" PRIx64 " count=0x%x req_one=%d",
395 offs, count, !!(flags & NBDKIT_FLAG_REQ_ONE));
396 r = next->extents (next, count, offs, flags, extents, err);
397 if (r == -1)
398 leave_simple (h, id, "Extents", r, err);
399 else {
400 FILE *fp;
401 CLEANUP_FREE char *str = NULL;
402 size_t i, n, len = 0;
404 fp = open_memstream (&str, &len);
405 if (fp != NULL) {
406 fprintf (fp, "extents=(");
407 n = nbdkit_extents_count (extents);
408 for (i = 0; i < n; ++i) {
409 bool comma = false;
410 struct nbdkit_extent e = nbdkit_get_extent (extents, i);
411 if (i > 0)
412 fprintf (fp, " ");
413 fprintf (fp, "0x%" PRIx64 " 0x%" PRIx64, e.offset, e.length);
414 fprintf (fp, " \"");
415 if ((e.type & NBDKIT_EXTENT_HOLE) != 0) {
416 fprintf (fp, "hole");
417 comma = true;
419 if ((e.type & NBDKIT_EXTENT_ZERO) != 0) {
420 if (comma) fprintf (fp, ",");
421 fprintf (fp, "zero");
423 fprintf (fp, "\"");
425 fprintf (fp, ") return=0");
426 fclose (fp);
427 leave (h, id, "Extents", "%s", str);
429 else
430 leave (h, id, "Extents", "");
432 return r;
435 /* Cache data. */
436 static int
437 log_cache (nbdkit_next *next,
438 void *handle, uint32_t count, uint64_t offs, uint32_t flags,
439 int *err)
441 struct handle *h = handle;
442 int r;
444 LOG (h, "Cache", r, err, "offset=0x%" PRIx64 " count=0x%x", offs, count);
446 assert (!flags);
447 return r = next->cache (next, count, offs, flags, err);
450 static struct nbdkit_filter filter = {
451 .name = "log",
452 .longname = "nbdkit log filter",
453 .config = log_config,
454 .config_help = log_config_help,
455 .unload = log_unload,
456 .get_ready = log_get_ready,
457 .after_fork = log_after_fork,
458 .list_exports = log_list_exports,
459 .preconnect = log_preconnect,
460 .open = log_open,
461 .close = log_close,
462 .prepare = log_prepare,
463 .finalize = log_finalize,
464 .pread = log_pread,
465 .pwrite = log_pwrite,
466 .flush = log_flush,
467 .trim = log_trim,
468 .zero = log_zero,
469 .extents = log_extents,
470 .cache = log_cache,
473 NBDKIT_REGISTER_FILTER (filter)