2 * logging.c - Centralised logging. Originated from the Linux-NTFS project.
4 * Copyright (c) 2005 Richard Russon
5 * Copyright (c) 2005-2008 Szabolcs Szakacsits
6 * Copyright (c) 2010 Jean-Pierre Andre
8 * This program/include file is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as published
10 * by the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program/include file is distributed in the hope that it will be
14 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
15 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program (in the main directory of the NTFS-3G
20 * distribution in the file COPYING); if not, write to the Free Software
21 * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
58 /* Some gcc 3.x, 4.[01].X crash with internal compiler error. */
59 #if __GNUC__ <= 3 || (__GNUC__ == 4 && __GNUC_MINOR__ <= 1)
60 # define BROKEN_GCC_FORMAT_ATTRIBUTE
62 # define BROKEN_GCC_FORMAT_ATTRIBUTE __attribute__((format(printf, 6, 0)))
66 * struct ntfs_logging - Control info for the logging system
67 * @levels: Bitfield of logging levels
68 * @flags: Flags which affect the output style
69 * @handler: Function to perform the actual logging
74 ntfs_log_handler
*handler BROKEN_GCC_FORMAT_ATTRIBUTE
;
79 * This struct controls all the logging within the library and tools.
81 static struct ntfs_logging ntfs_log
= {
83 NTFS_LOG_LEVEL_DEBUG
| NTFS_LOG_LEVEL_TRACE
| NTFS_LOG_LEVEL_ENTER
|
84 NTFS_LOG_LEVEL_LEAVE
|
86 NTFS_LOG_LEVEL_INFO
| NTFS_LOG_LEVEL_QUIET
| NTFS_LOG_LEVEL_WARNING
|
87 NTFS_LOG_LEVEL_ERROR
| NTFS_LOG_LEVEL_PERROR
| NTFS_LOG_LEVEL_CRITICAL
|
88 NTFS_LOG_LEVEL_PROGRESS
,
89 NTFS_LOG_FLAG_ONLYNAME
,
91 ntfs_log_handler_outerr
99 * ntfs_log_get_levels - Get a list of the current logging levels
101 * Find out which logging levels are enabled.
103 * Returns: Log levels in a 32-bit field
105 u32
ntfs_log_get_levels(void)
107 return ntfs_log
.levels
;
111 * ntfs_log_set_levels - Enable extra logging levels
112 * @levels: 32-bit field of log levels to set
114 * Enable one or more logging levels.
115 * The logging levels are named: NTFS_LOG_LEVEL_*.
117 * Returns: Log levels that were enabled before the call
119 u32
ntfs_log_set_levels(u32 levels
)
122 old
= ntfs_log
.levels
;
123 ntfs_log
.levels
|= levels
;
128 * ntfs_log_clear_levels - Disable some logging levels
129 * @levels: 32-bit field of log levels to clear
131 * Disable one or more logging levels.
132 * The logging levels are named: NTFS_LOG_LEVEL_*.
134 * Returns: Log levels that were enabled before the call
136 u32
ntfs_log_clear_levels(u32 levels
)
139 old
= ntfs_log
.levels
;
140 ntfs_log
.levels
&= (~levels
);
146 * ntfs_log_get_flags - Get a list of logging style flags
148 * Find out which logging flags are enabled.
150 * Returns: Logging flags in a 32-bit field
152 u32
ntfs_log_get_flags(void)
154 return ntfs_log
.flags
;
158 * ntfs_log_set_flags - Enable extra logging style flags
159 * @flags: 32-bit field of logging flags to set
161 * Enable one or more logging flags.
162 * The log flags are named: NTFS_LOG_LEVEL_*.
164 * Returns: Logging flags that were enabled before the call
166 u32
ntfs_log_set_flags(u32 flags
)
169 old
= ntfs_log
.flags
;
170 ntfs_log
.flags
|= flags
;
175 * ntfs_log_clear_flags - Disable some logging styles
176 * @flags: 32-bit field of logging flags to clear
178 * Disable one or more logging flags.
179 * The log flags are named: NTFS_LOG_LEVEL_*.
181 * Returns: Logging flags that were enabled before the call
183 u32
ntfs_log_clear_flags(u32 flags
)
186 old
= ntfs_log
.flags
;
187 ntfs_log
.flags
&= (~flags
);
193 * ntfs_log_get_stream - Default output streams for logging levels
196 * By default, urgent messages are sent to "stderr".
197 * Other messages are sent to "stdout".
199 * Returns: "string" Prefix to be used
201 static FILE * ntfs_log_get_stream(u32 level
)
206 case NTFS_LOG_LEVEL_INFO
:
207 case NTFS_LOG_LEVEL_QUIET
:
208 case NTFS_LOG_LEVEL_PROGRESS
:
209 case NTFS_LOG_LEVEL_VERBOSE
:
213 case NTFS_LOG_LEVEL_DEBUG
:
214 case NTFS_LOG_LEVEL_TRACE
:
215 case NTFS_LOG_LEVEL_ENTER
:
216 case NTFS_LOG_LEVEL_LEAVE
:
217 case NTFS_LOG_LEVEL_WARNING
:
218 case NTFS_LOG_LEVEL_ERROR
:
219 case NTFS_LOG_LEVEL_CRITICAL
:
220 case NTFS_LOG_LEVEL_PERROR
:
230 * ntfs_log_get_prefix - Default prefixes for logging levels
231 * @level: Log level to be prefixed
233 * Prefixing the logging output can make it easier to parse.
235 * Returns: "string" Prefix to be used
237 static const char * ntfs_log_get_prefix(u32 level
)
242 case NTFS_LOG_LEVEL_DEBUG
:
245 case NTFS_LOG_LEVEL_TRACE
:
248 case NTFS_LOG_LEVEL_QUIET
:
251 case NTFS_LOG_LEVEL_INFO
:
254 case NTFS_LOG_LEVEL_VERBOSE
:
255 prefix
= "VERBOSE: ";
257 case NTFS_LOG_LEVEL_PROGRESS
:
258 prefix
= "PROGRESS: ";
260 case NTFS_LOG_LEVEL_WARNING
:
261 prefix
= "WARNING: ";
263 case NTFS_LOG_LEVEL_ERROR
:
266 case NTFS_LOG_LEVEL_PERROR
:
269 case NTFS_LOG_LEVEL_CRITICAL
:
270 prefix
= "CRITICAL: ";
282 * ntfs_log_set_handler - Provide an alternate logging handler
283 * @handler: function to perform the logging
285 * This alternate handler will be called for all future logging requests.
286 * If no @handler is specified, logging will revert to the default handler.
288 void ntfs_log_set_handler(ntfs_log_handler
*handler
)
291 ntfs_log
.handler
= handler
;
293 if (handler
== ntfs_log_handler_syslog
)
294 openlog("ntfs-3g", LOG_PID
, LOG_USER
);
297 ntfs_log
.handler
= ntfs_log_handler_null
;
301 * ntfs_log_redirect - Pass on the request to the real handler
302 * @function: Function in which the log line occurred
303 * @file: File in which the log line occurred
304 * @line: Line number on which the log line occurred
305 * @level: Level at which the line is logged
306 * @data: User specified data, possibly specific to a handler
307 * @format: printf-style formatting string
308 * @...: Arguments to be formatted
310 * This is just a redirector function. The arguments are simply passed to the
311 * main logging handler (as defined in the global logging struct @ntfs_log).
313 * Returns: -1 Error occurred
314 * 0 Message wasn't logged
315 * num Number of output characters
317 int ntfs_log_redirect(const char *function
, const char *file
,
318 int line
, u32 level
, void *data
, const char *format
, ...)
324 if (!(ntfs_log
.levels
& level
)) /* Don't log this message */
327 va_start(args
, format
);
329 ret
= ntfs_log
.handler(function
, file
, line
, level
, data
, format
, args
);
338 * ntfs_log_handler_syslog - syslog logging handler
339 * @function: Function in which the log line occurred
340 * @file: File in which the log line occurred
341 * @line: Line number on which the log line occurred
342 * @level: Level at which the line is logged
343 * @data: User specified data, possibly specific to a handler
344 * @format: printf-style formatting string
345 * @args: Arguments to be formatted
347 * A simple syslog logging handler. Ignores colors.
349 * Returns: -1 Error occurred
350 * 0 Message wasn't logged
351 * num Number of output characters
357 #define LOG_LINE_LEN 512
359 int ntfs_log_handler_syslog(const char *function
__attribute__((unused
)),
360 const char *file
__attribute__((unused
)),
361 int line
__attribute__((unused
)), u32 level
,
362 void *data
__attribute__((unused
)),
363 const char *format
, va_list args
)
365 char logbuf
[LOG_LINE_LEN
];
366 int ret
, olderr
= errno
;
369 if ((level
& NTFS_LOG_LEVEL_PERROR
) && errno
== ENOSPC
)
372 ret
= vsnprintf(logbuf
, LOG_LINE_LEN
, format
, args
);
374 vsyslog(LOG_NOTICE
, format
, args
);
379 if ((LOG_LINE_LEN
> ret
+ 3) && (level
& NTFS_LOG_LEVEL_PERROR
)) {
380 strncat(logbuf
, ": ", LOG_LINE_LEN
- ret
- 1);
381 strncat(logbuf
, strerror(olderr
), LOG_LINE_LEN
- (ret
+ 3));
382 ret
= strlen(logbuf
);
385 syslog(LOG_NOTICE
, "%s", logbuf
);
393 * Early logging before the logs are redirected
395 * (not quite satisfactory : this appears before the ntfs-g banner,
396 * and with a different pid)
399 void ntfs_log_early_error(const char *format
, ...)
403 va_start(args
, format
);
405 openlog("ntfs-3g", LOG_PID
, LOG_USER
);
406 ntfs_log_handler_syslog(NULL
, NULL
, 0,
407 NTFS_LOG_LEVEL_ERROR
, NULL
,
410 vfprintf(stderr
,format
,args
);
416 * ntfs_log_handler_fprintf - Basic logging handler
417 * @function: Function in which the log line occurred
418 * @file: File in which the log line occurred
419 * @line: Line number on which the log line occurred
420 * @level: Level at which the line is logged
421 * @data: User specified data, possibly specific to a handler
422 * @format: printf-style formatting string
423 * @args: Arguments to be formatted
425 * A simple logging handler. This is where the log line is finally displayed.
426 * It is more likely that you will want to set the handler to either
427 * ntfs_log_handler_outerr or ntfs_log_handler_stderr.
429 * Note: For this handler, @data is a pointer to a FILE output stream.
430 * If @data is NULL, nothing will be displayed.
432 * Returns: -1 Error occurred
433 * 0 Message wasn't logged
434 * num Number of output characters
436 int ntfs_log_handler_fprintf(const char *function
, const char *file
,
437 int line
, u32 level
, void *data
, const char *format
, va_list args
)
446 if (!data
) /* Interpret data as a FILE stream. */
447 return 0; /* If it's NULL, we can't do anything. */
448 stream
= (FILE*)data
;
451 if (level
== NTFS_LOG_LEVEL_LEAVE
) {
457 for (i
= 0; i
< tab
; i
++)
458 ret
+= fprintf(stream
, " ");
460 if ((ntfs_log
.flags
& NTFS_LOG_FLAG_ONLYNAME
) &&
461 (strchr(file
, PATH_SEP
))) /* Abbreviate the filename */
462 file
= strrchr(file
, PATH_SEP
) + 1;
464 if (ntfs_log
.flags
& NTFS_LOG_FLAG_PREFIX
) /* Prefix the output */
465 ret
+= fprintf(stream
, "%s", ntfs_log_get_prefix(level
));
467 if (ntfs_log
.flags
& NTFS_LOG_FLAG_FILENAME
) /* Source filename */
468 ret
+= fprintf(stream
, "%s ", file
);
470 if (ntfs_log
.flags
& NTFS_LOG_FLAG_LINE
) /* Source line number */
471 ret
+= fprintf(stream
, "(%d) ", line
);
473 if ((ntfs_log
.flags
& NTFS_LOG_FLAG_FUNCTION
) || /* Source function */
474 (level
& NTFS_LOG_LEVEL_TRACE
) || (level
& NTFS_LOG_LEVEL_ENTER
))
475 ret
+= fprintf(stream
, "%s(): ", function
);
477 ret
+= vfprintf(stream
, format
, args
);
479 if (level
& NTFS_LOG_LEVEL_PERROR
)
480 ret
+= fprintf(stream
, ": %s\n", strerror(olderr
));
483 if (level
== NTFS_LOG_LEVEL_ENTER
)
492 * ntfs_log_handler_null - Null logging handler (no output)
493 * @function: Function in which the log line occurred
494 * @file: File in which the log line occurred
495 * @line: Line number on which the log line occurred
496 * @level: Level at which the line is logged
497 * @data: User specified data, possibly specific to a handler
498 * @format: printf-style formatting string
499 * @args: Arguments to be formatted
501 * This handler produces no output. It provides a way to temporarily disable
502 * logging, without having to change the levels and flags.
504 * Returns: 0 Message wasn't logged
506 int ntfs_log_handler_null(const char *function
__attribute__((unused
)), const char *file
__attribute__((unused
)),
507 int line
__attribute__((unused
)), u32 level
__attribute__((unused
)), void *data
__attribute__((unused
)),
508 const char *format
__attribute__((unused
)), va_list args
__attribute__((unused
)))
514 * ntfs_log_handler_stdout - All logs go to stdout
515 * @function: Function in which the log line occurred
516 * @file: File in which the log line occurred
517 * @line: Line number on which the log line occurred
518 * @level: Level at which the line is logged
519 * @data: User specified data, possibly specific to a handler
520 * @format: printf-style formatting string
521 * @args: Arguments to be formatted
523 * Display a log message to stdout.
525 * Note: For this handler, @data is a pointer to a FILE output stream.
526 * If @data is NULL, then stdout will be used.
528 * Note: This function calls ntfs_log_handler_fprintf to do the main work.
530 * Returns: -1 Error occurred
531 * 0 Message wasn't logged
532 * num Number of output characters
534 int ntfs_log_handler_stdout(const char *function
, const char *file
,
535 int line
, u32 level
, void *data
, const char *format
, va_list args
)
540 return ntfs_log_handler_fprintf(function
, file
, line
, level
, data
, format
, args
);
544 * ntfs_log_handler_outerr - Logs go to stdout/stderr depending on level
545 * @function: Function in which the log line occurred
546 * @file: File in which the log line occurred
547 * @line: Line number on which the log line occurred
548 * @level: Level at which the line is logged
549 * @data: User specified data, possibly specific to a handler
550 * @format: printf-style formatting string
551 * @args: Arguments to be formatted
553 * Display a log message. The output stream will be determined by the log
556 * Note: For this handler, @data is a pointer to a FILE output stream.
557 * If @data is NULL, the function ntfs_log_get_stream will be called
559 * Note: This function calls ntfs_log_handler_fprintf to do the main work.
561 * Returns: -1 Error occurred
562 * 0 Message wasn't logged
563 * num Number of output characters
565 int ntfs_log_handler_outerr(const char *function
, const char *file
,
566 int line
, u32 level
, void *data
, const char *format
, va_list args
)
569 data
= ntfs_log_get_stream(level
);
571 return ntfs_log_handler_fprintf(function
, file
, line
, level
, data
, format
, args
);
575 * ntfs_log_handler_stderr - All logs go to stderr
576 * @function: Function in which the log line occurred
577 * @file: File in which the log line occurred
578 * @line: Line number on which the log line occurred
579 * @level: Level at which the line is logged
580 * @data: User specified data, possibly specific to a handler
581 * @format: printf-style formatting string
582 * @args: Arguments to be formatted
584 * Display a log message to stderr.
586 * Note: For this handler, @data is a pointer to a FILE output stream.
587 * If @data is NULL, then stdout will be used.
589 * Note: This function calls ntfs_log_handler_fprintf to do the main work.
591 * Returns: -1 Error occurred
592 * 0 Message wasn't logged
593 * num Number of output characters
595 int ntfs_log_handler_stderr(const char *function
, const char *file
,
596 int line
, u32 level
, void *data
, const char *format
, va_list args
)
601 return ntfs_log_handler_fprintf(function
, file
, line
, level
, data
, format
, args
);
606 * ntfs_log_parse_option - Act upon command line options
607 * @option: Option flag
609 * Delegate some of the work of parsing the command line. All the options begin
610 * with "--log-". Options cause log levels to be enabled in @ntfs_log (the
611 * global logging structure).
613 * Note: The "colour" option changes the logging handler.
615 * Returns: TRUE Option understood
616 * FALSE Invalid log option
618 BOOL
ntfs_log_parse_option(const char *option
)
620 if (strcmp(option
, "--log-debug") == 0) {
621 ntfs_log_set_levels(NTFS_LOG_LEVEL_DEBUG
);
623 } else if (strcmp(option
, "--log-verbose") == 0) {
624 ntfs_log_set_levels(NTFS_LOG_LEVEL_VERBOSE
);
626 } else if (strcmp(option
, "--log-quiet") == 0) {
627 ntfs_log_clear_levels(NTFS_LOG_LEVEL_QUIET
);
629 } else if (strcmp(option
, "--log-trace") == 0) {
630 ntfs_log_set_levels(NTFS_LOG_LEVEL_TRACE
);
634 ntfs_log_debug("Unknown logging option '%s'\n", option
);