4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
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
47 #include <sys/types.h>
49 #include <nbdkit-filter.h>
53 #include "windows-compat.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"
63 const char *logfilename
;
65 const char *logscript
;
67 pthread_mutex_t lock
= PTHREAD_MUTEX_INITIALIZER
;
77 /* Called for each key=value passed on the command line. */
79 log_config (nbdkit_next_config
*next
, nbdkit_backend
*nxdata
,
80 const char *key
, const char *value
)
82 if (strcmp (key
, "logfile") == 0) {
86 if (strcmp (key
, "logappend") == 0) {
87 append
= nbdkit_parse_bool (value
);
92 if (strcmp (key
, "logscript") == 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. */
106 log_get_ready (int thread_model
)
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
),
121 nbdkit_error ("open: %s: %m", logfilename
);
124 logfile
= fdopen (fd
, append
? "a" : "w");
126 nbdkit_error ("fdopen: %s: %m", logfilename
);
132 saved_pid
= getpid ();
134 print (NULL
, "Ready", "thread_model=%d", thread_model
);
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", "");
150 log_list_exports (nbdkit_next_list_exports
*next
, nbdkit_backend
*nxdata
,
151 int readonly
, int is_tls
,
152 struct nbdkit_exports
*exports
)
158 enter (NULL
, ++id
, "ListExports", "readonly=%d tls=%d", readonly
, is_tls
);
159 r
= next (nxdata
, readonly
, exports
);
162 leave_simple (NULL
, id
, "ListExports", r
, &err
);
166 CLEANUP_FREE
char *str
= NULL
;
167 size_t i
, n
, len
= 0;
169 fp
= open_memstream (&str
, &len
);
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
);
177 shell_quote (e
.name
, fp
);
179 fprintf (fp
, ") return=0");
181 leave (NULL
, id
, "ListExports", "%s", str
);
184 leave (NULL
, id
, "ListExports", "");
190 log_preconnect (nbdkit_next_preconnect
*next
, nbdkit_backend
*nxdata
,
197 enter (NULL
, ++id
, "Preconnect", "readonly=%d", readonly
);
198 r
= next (nxdata
, readonly
);
201 leave_simple (NULL
, id
, "Preconnect", r
, &err
);
205 /* Open a connection. */
207 log_open (nbdkit_next_open
*next
, nbdkit_context
*nxdata
,
208 int readonly
, const char *exportname
, int is_tls
)
212 if (next (nxdata
, readonly
, exportname
) == -1)
215 h
= malloc (sizeof *h
);
217 nbdkit_error ("malloc: %m");
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
225 h
->exportname
= nbdkit_strdup_intern (exportname
);
226 if (h
->exportname
== NULL
) {
232 ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&lock
);
233 h
->connection
= ++connections
;
239 log_close (void *handle
)
245 log_prepare (nbdkit_next
*next
, void *handle
,
249 CLEANUP_FREE
char *str
= NULL
;
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)
270 fp
= open_memstream (&str
, &len
);
272 fprintf (fp
, "export=");
273 shell_quote (exportname
, 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
);
282 print (h
, "Connect", "%s", str
);
285 print (h
, "Connect", "");
291 log_finalize (nbdkit_next
*next
, void *handle
)
293 struct handle
*h
= handle
;
295 print (h
, "Disconnect", "transactions=%" PRId64
, h
->id
);
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
;
308 LOG (h
, "Read", r
, err
, "offset=0x%" PRIx64
" count=0x%x", offs
, count
);
311 return r
= next
->pread (next
, buf
, count
, offs
, flags
, err
);
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
;
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
);
333 log_flush (nbdkit_next
*next
, void *handle
,
334 uint32_t flags
, int *err
)
336 struct handle
*h
= handle
;
339 LOG (h
, "Flush", r
, err
, "");
342 return r
= next
->flush (next
, flags
, err
);
347 log_trim (nbdkit_next
*next
,
348 void *handle
, uint32_t count
, uint64_t offs
, uint32_t flags
,
351 struct handle
*h
= handle
;
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
);
364 log_zero (nbdkit_next
*next
,
365 void *handle
, uint32_t count
, uint64_t offs
, uint32_t flags
,
368 struct handle
*h
= handle
;
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
);
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
);
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
);
398 leave_simple (h
, id
, "Extents", r
, err
);
401 CLEANUP_FREE
char *str
= NULL
;
402 size_t i
, n
, len
= 0;
404 fp
= open_memstream (&str
, &len
);
406 fprintf (fp
, "extents=(");
407 n
= nbdkit_extents_count (extents
);
408 for (i
= 0; i
< n
; ++i
) {
410 struct nbdkit_extent e
= nbdkit_get_extent (extents
, i
);
413 fprintf (fp
, "0x%" PRIx64
" 0x%" PRIx64
, e
.offset
, e
.length
);
415 if ((e
.type
& NBDKIT_EXTENT_HOLE
) != 0) {
416 fprintf (fp
, "hole");
419 if ((e
.type
& NBDKIT_EXTENT_ZERO
) != 0) {
420 if (comma
) fprintf (fp
, ",");
421 fprintf (fp
, "zero");
425 fprintf (fp
, ") return=0");
427 leave (h
, id
, "Extents", "%s", str
);
430 leave (h
, id
, "Extents", "");
437 log_cache (nbdkit_next
*next
,
438 void *handle
, uint32_t count
, uint64_t offs
, uint32_t flags
,
441 struct handle
*h
= handle
;
444 LOG (h
, "Cache", r
, err
, "offset=0x%" PRIx64
" count=0x%x", offs
, count
);
447 return r
= next
->cache (next
, count
, offs
, flags
, err
);
450 static struct nbdkit_filter filter
= {
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
,
462 .prepare
= log_prepare
,
463 .finalize
= log_finalize
,
465 .pwrite
= log_pwrite
,
469 .extents
= log_extents
,
473 NBDKIT_REGISTER_FILTER (filter
)