1987da915Sopenharmony_ci/**
2987da915Sopenharmony_ci * logging.c - Centralised logging.  Originated from the Linux-NTFS project.
3987da915Sopenharmony_ci *
4987da915Sopenharmony_ci * Copyright (c) 2005 Richard Russon
5987da915Sopenharmony_ci * Copyright (c) 2005-2008 Szabolcs Szakacsits
6987da915Sopenharmony_ci * Copyright (c) 2010      Jean-Pierre Andre
7987da915Sopenharmony_ci *
8987da915Sopenharmony_ci * This program/include file is free software; you can redistribute it and/or
9987da915Sopenharmony_ci * modify it under the terms of the GNU General Public License as published
10987da915Sopenharmony_ci * by the Free Software Foundation; either version 2 of the License, or
11987da915Sopenharmony_ci * (at your option) any later version.
12987da915Sopenharmony_ci *
13987da915Sopenharmony_ci * This program/include file is distributed in the hope that it will be
14987da915Sopenharmony_ci * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
15987da915Sopenharmony_ci * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16987da915Sopenharmony_ci * GNU General Public License for more details.
17987da915Sopenharmony_ci *
18987da915Sopenharmony_ci * You should have received a copy of the GNU General Public License
19987da915Sopenharmony_ci * along with this program (in the main directory of the NTFS-3G
20987da915Sopenharmony_ci * distribution in the file COPYING); if not, write to the Free Software
21987da915Sopenharmony_ci * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22987da915Sopenharmony_ci */
23987da915Sopenharmony_ci
24987da915Sopenharmony_ci#ifdef HAVE_CONFIG_H
25987da915Sopenharmony_ci#include "config.h"
26987da915Sopenharmony_ci#endif
27987da915Sopenharmony_ci
28987da915Sopenharmony_ci#ifdef HAVE_STDIO_H
29987da915Sopenharmony_ci#include <stdio.h>
30987da915Sopenharmony_ci#endif
31987da915Sopenharmony_ci#ifdef HAVE_ERRNO_H
32987da915Sopenharmony_ci#include <errno.h>
33987da915Sopenharmony_ci#endif
34987da915Sopenharmony_ci#ifdef HAVE_STDARG_H
35987da915Sopenharmony_ci#include <stdarg.h>
36987da915Sopenharmony_ci#endif
37987da915Sopenharmony_ci#ifdef HAVE_STRING_H
38987da915Sopenharmony_ci#include <string.h>
39987da915Sopenharmony_ci#endif
40987da915Sopenharmony_ci#ifdef HAVE_STDLIB_H
41987da915Sopenharmony_ci#include <stdlib.h>
42987da915Sopenharmony_ci#endif
43987da915Sopenharmony_ci#ifdef HAVE_SYSLOG_H
44987da915Sopenharmony_ci#include <syslog.h>
45987da915Sopenharmony_ci#endif
46987da915Sopenharmony_ci
47987da915Sopenharmony_ci#include "logging.h"
48987da915Sopenharmony_ci#include "misc.h"
49987da915Sopenharmony_ci
50987da915Sopenharmony_ci#ifndef PATH_SEP
51987da915Sopenharmony_ci#define PATH_SEP '/'
52987da915Sopenharmony_ci#endif
53987da915Sopenharmony_ci
54987da915Sopenharmony_ci#ifdef DEBUG
55987da915Sopenharmony_cistatic int tab;
56987da915Sopenharmony_ci#endif
57987da915Sopenharmony_ci
58987da915Sopenharmony_ci/* Some gcc 3.x, 4.[01].X crash with internal compiler error. */
59987da915Sopenharmony_ci#if __GNUC__ <= 3 || (__GNUC__ == 4 && __GNUC_MINOR__ <= 1)
60987da915Sopenharmony_ci# define  BROKEN_GCC_FORMAT_ATTRIBUTE
61987da915Sopenharmony_ci#else
62987da915Sopenharmony_ci# define  BROKEN_GCC_FORMAT_ATTRIBUTE __attribute__((format(printf, 6, 0)))
63987da915Sopenharmony_ci#endif
64987da915Sopenharmony_ci
65987da915Sopenharmony_ci/**
66987da915Sopenharmony_ci * struct ntfs_logging - Control info for the logging system
67987da915Sopenharmony_ci * @levels:	Bitfield of logging levels
68987da915Sopenharmony_ci * @flags:	Flags which affect the output style
69987da915Sopenharmony_ci * @handler:	Function to perform the actual logging
70987da915Sopenharmony_ci */
71987da915Sopenharmony_cistruct ntfs_logging {
72987da915Sopenharmony_ci	u32 levels;
73987da915Sopenharmony_ci	u32 flags;
74987da915Sopenharmony_ci	ntfs_log_handler *handler BROKEN_GCC_FORMAT_ATTRIBUTE;
75987da915Sopenharmony_ci};
76987da915Sopenharmony_ci
77987da915Sopenharmony_ci/**
78987da915Sopenharmony_ci * ntfs_log
79987da915Sopenharmony_ci * This struct controls all the logging within the library and tools.
80987da915Sopenharmony_ci */
81987da915Sopenharmony_cistatic struct ntfs_logging ntfs_log = {
82987da915Sopenharmony_ci#ifdef DEBUG
83987da915Sopenharmony_ci	NTFS_LOG_LEVEL_DEBUG | NTFS_LOG_LEVEL_TRACE | NTFS_LOG_LEVEL_ENTER |
84987da915Sopenharmony_ci	NTFS_LOG_LEVEL_LEAVE |
85987da915Sopenharmony_ci#endif
86987da915Sopenharmony_ci	NTFS_LOG_LEVEL_INFO | NTFS_LOG_LEVEL_QUIET | NTFS_LOG_LEVEL_WARNING |
87987da915Sopenharmony_ci	NTFS_LOG_LEVEL_ERROR | NTFS_LOG_LEVEL_PERROR | NTFS_LOG_LEVEL_CRITICAL |
88987da915Sopenharmony_ci	NTFS_LOG_LEVEL_PROGRESS,
89987da915Sopenharmony_ci	NTFS_LOG_FLAG_ONLYNAME,
90987da915Sopenharmony_ci#ifdef DEBUG
91987da915Sopenharmony_ci	ntfs_log_handler_outerr
92987da915Sopenharmony_ci#else
93987da915Sopenharmony_ci	ntfs_log_handler_null
94987da915Sopenharmony_ci#endif
95987da915Sopenharmony_ci};
96987da915Sopenharmony_ci
97987da915Sopenharmony_ci
98987da915Sopenharmony_ci/**
99987da915Sopenharmony_ci * ntfs_log_get_levels - Get a list of the current logging levels
100987da915Sopenharmony_ci *
101987da915Sopenharmony_ci * Find out which logging levels are enabled.
102987da915Sopenharmony_ci *
103987da915Sopenharmony_ci * Returns:  Log levels in a 32-bit field
104987da915Sopenharmony_ci */
105987da915Sopenharmony_ciu32 ntfs_log_get_levels(void)
106987da915Sopenharmony_ci{
107987da915Sopenharmony_ci	return ntfs_log.levels;
108987da915Sopenharmony_ci}
109987da915Sopenharmony_ci
110987da915Sopenharmony_ci/**
111987da915Sopenharmony_ci * ntfs_log_set_levels - Enable extra logging levels
112987da915Sopenharmony_ci * @levels:	32-bit field of log levels to set
113987da915Sopenharmony_ci *
114987da915Sopenharmony_ci * Enable one or more logging levels.
115987da915Sopenharmony_ci * The logging levels are named: NTFS_LOG_LEVEL_*.
116987da915Sopenharmony_ci *
117987da915Sopenharmony_ci * Returns:  Log levels that were enabled before the call
118987da915Sopenharmony_ci */
119987da915Sopenharmony_ciu32 ntfs_log_set_levels(u32 levels)
120987da915Sopenharmony_ci{
121987da915Sopenharmony_ci	u32 old;
122987da915Sopenharmony_ci	old = ntfs_log.levels;
123987da915Sopenharmony_ci	ntfs_log.levels |= levels;
124987da915Sopenharmony_ci	return old;
125987da915Sopenharmony_ci}
126987da915Sopenharmony_ci
127987da915Sopenharmony_ci/**
128987da915Sopenharmony_ci * ntfs_log_clear_levels - Disable some logging levels
129987da915Sopenharmony_ci * @levels:	32-bit field of log levels to clear
130987da915Sopenharmony_ci *
131987da915Sopenharmony_ci * Disable one or more logging levels.
132987da915Sopenharmony_ci * The logging levels are named: NTFS_LOG_LEVEL_*.
133987da915Sopenharmony_ci *
134987da915Sopenharmony_ci * Returns:  Log levels that were enabled before the call
135987da915Sopenharmony_ci */
136987da915Sopenharmony_ciu32 ntfs_log_clear_levels(u32 levels)
137987da915Sopenharmony_ci{
138987da915Sopenharmony_ci	u32 old;
139987da915Sopenharmony_ci	old = ntfs_log.levels;
140987da915Sopenharmony_ci	ntfs_log.levels &= (~levels);
141987da915Sopenharmony_ci	return old;
142987da915Sopenharmony_ci}
143987da915Sopenharmony_ci
144987da915Sopenharmony_ci
145987da915Sopenharmony_ci/**
146987da915Sopenharmony_ci * ntfs_log_get_flags - Get a list of logging style flags
147987da915Sopenharmony_ci *
148987da915Sopenharmony_ci * Find out which logging flags are enabled.
149987da915Sopenharmony_ci *
150987da915Sopenharmony_ci * Returns:  Logging flags in a 32-bit field
151987da915Sopenharmony_ci */
152987da915Sopenharmony_ciu32 ntfs_log_get_flags(void)
153987da915Sopenharmony_ci{
154987da915Sopenharmony_ci	return ntfs_log.flags;
155987da915Sopenharmony_ci}
156987da915Sopenharmony_ci
157987da915Sopenharmony_ci/**
158987da915Sopenharmony_ci * ntfs_log_set_flags - Enable extra logging style flags
159987da915Sopenharmony_ci * @flags:	32-bit field of logging flags to set
160987da915Sopenharmony_ci *
161987da915Sopenharmony_ci * Enable one or more logging flags.
162987da915Sopenharmony_ci * The log flags are named: NTFS_LOG_LEVEL_*.
163987da915Sopenharmony_ci *
164987da915Sopenharmony_ci * Returns:  Logging flags that were enabled before the call
165987da915Sopenharmony_ci */
166987da915Sopenharmony_ciu32 ntfs_log_set_flags(u32 flags)
167987da915Sopenharmony_ci{
168987da915Sopenharmony_ci	u32 old;
169987da915Sopenharmony_ci	old = ntfs_log.flags;
170987da915Sopenharmony_ci	ntfs_log.flags |= flags;
171987da915Sopenharmony_ci	return old;
172987da915Sopenharmony_ci}
173987da915Sopenharmony_ci
174987da915Sopenharmony_ci/**
175987da915Sopenharmony_ci * ntfs_log_clear_flags - Disable some logging styles
176987da915Sopenharmony_ci * @flags:	32-bit field of logging flags to clear
177987da915Sopenharmony_ci *
178987da915Sopenharmony_ci * Disable one or more logging flags.
179987da915Sopenharmony_ci * The log flags are named: NTFS_LOG_LEVEL_*.
180987da915Sopenharmony_ci *
181987da915Sopenharmony_ci * Returns:  Logging flags that were enabled before the call
182987da915Sopenharmony_ci */
183987da915Sopenharmony_ciu32 ntfs_log_clear_flags(u32 flags)
184987da915Sopenharmony_ci{
185987da915Sopenharmony_ci	u32 old;
186987da915Sopenharmony_ci	old = ntfs_log.flags;
187987da915Sopenharmony_ci	ntfs_log.flags &= (~flags);
188987da915Sopenharmony_ci	return old;
189987da915Sopenharmony_ci}
190987da915Sopenharmony_ci
191987da915Sopenharmony_ci
192987da915Sopenharmony_ci/**
193987da915Sopenharmony_ci * ntfs_log_get_stream - Default output streams for logging levels
194987da915Sopenharmony_ci * @level:	Log level
195987da915Sopenharmony_ci *
196987da915Sopenharmony_ci * By default, urgent messages are sent to "stderr".
197987da915Sopenharmony_ci * Other messages are sent to "stdout".
198987da915Sopenharmony_ci *
199987da915Sopenharmony_ci * Returns:  "string"  Prefix to be used
200987da915Sopenharmony_ci */
201987da915Sopenharmony_cistatic FILE * ntfs_log_get_stream(u32 level)
202987da915Sopenharmony_ci{
203987da915Sopenharmony_ci	FILE *stream;
204987da915Sopenharmony_ci
205987da915Sopenharmony_ci	switch (level) {
206987da915Sopenharmony_ci		case NTFS_LOG_LEVEL_INFO:
207987da915Sopenharmony_ci		case NTFS_LOG_LEVEL_QUIET:
208987da915Sopenharmony_ci		case NTFS_LOG_LEVEL_PROGRESS:
209987da915Sopenharmony_ci		case NTFS_LOG_LEVEL_VERBOSE:
210987da915Sopenharmony_ci			stream = stdout;
211987da915Sopenharmony_ci			break;
212987da915Sopenharmony_ci
213987da915Sopenharmony_ci		case NTFS_LOG_LEVEL_DEBUG:
214987da915Sopenharmony_ci		case NTFS_LOG_LEVEL_TRACE:
215987da915Sopenharmony_ci		case NTFS_LOG_LEVEL_ENTER:
216987da915Sopenharmony_ci		case NTFS_LOG_LEVEL_LEAVE:
217987da915Sopenharmony_ci		case NTFS_LOG_LEVEL_WARNING:
218987da915Sopenharmony_ci		case NTFS_LOG_LEVEL_ERROR:
219987da915Sopenharmony_ci		case NTFS_LOG_LEVEL_CRITICAL:
220987da915Sopenharmony_ci		case NTFS_LOG_LEVEL_PERROR:
221987da915Sopenharmony_ci		default:
222987da915Sopenharmony_ci			stream = stderr;
223987da915Sopenharmony_ci			break;
224987da915Sopenharmony_ci	}
225987da915Sopenharmony_ci
226987da915Sopenharmony_ci	return stream;
227987da915Sopenharmony_ci}
228987da915Sopenharmony_ci
229987da915Sopenharmony_ci/**
230987da915Sopenharmony_ci * ntfs_log_get_prefix - Default prefixes for logging levels
231987da915Sopenharmony_ci * @level:	Log level to be prefixed
232987da915Sopenharmony_ci *
233987da915Sopenharmony_ci * Prefixing the logging output can make it easier to parse.
234987da915Sopenharmony_ci *
235987da915Sopenharmony_ci * Returns:  "string"  Prefix to be used
236987da915Sopenharmony_ci */
237987da915Sopenharmony_cistatic const char * ntfs_log_get_prefix(u32 level)
238987da915Sopenharmony_ci{
239987da915Sopenharmony_ci	const char *prefix;
240987da915Sopenharmony_ci
241987da915Sopenharmony_ci	switch (level) {
242987da915Sopenharmony_ci		case NTFS_LOG_LEVEL_DEBUG:
243987da915Sopenharmony_ci			prefix = "DEBUG: ";
244987da915Sopenharmony_ci			break;
245987da915Sopenharmony_ci		case NTFS_LOG_LEVEL_TRACE:
246987da915Sopenharmony_ci			prefix = "TRACE: ";
247987da915Sopenharmony_ci			break;
248987da915Sopenharmony_ci		case NTFS_LOG_LEVEL_QUIET:
249987da915Sopenharmony_ci			prefix = "QUIET: ";
250987da915Sopenharmony_ci			break;
251987da915Sopenharmony_ci		case NTFS_LOG_LEVEL_INFO:
252987da915Sopenharmony_ci			prefix = "INFO: ";
253987da915Sopenharmony_ci			break;
254987da915Sopenharmony_ci		case NTFS_LOG_LEVEL_VERBOSE:
255987da915Sopenharmony_ci			prefix = "VERBOSE: ";
256987da915Sopenharmony_ci			break;
257987da915Sopenharmony_ci		case NTFS_LOG_LEVEL_PROGRESS:
258987da915Sopenharmony_ci			prefix = "PROGRESS: ";
259987da915Sopenharmony_ci			break;
260987da915Sopenharmony_ci		case NTFS_LOG_LEVEL_WARNING:
261987da915Sopenharmony_ci			prefix = "WARNING: ";
262987da915Sopenharmony_ci			break;
263987da915Sopenharmony_ci		case NTFS_LOG_LEVEL_ERROR:
264987da915Sopenharmony_ci			prefix = "ERROR: ";
265987da915Sopenharmony_ci			break;
266987da915Sopenharmony_ci		case NTFS_LOG_LEVEL_PERROR:
267987da915Sopenharmony_ci			prefix = "ERROR: ";
268987da915Sopenharmony_ci			break;
269987da915Sopenharmony_ci		case NTFS_LOG_LEVEL_CRITICAL:
270987da915Sopenharmony_ci			prefix = "CRITICAL: ";
271987da915Sopenharmony_ci			break;
272987da915Sopenharmony_ci		default:
273987da915Sopenharmony_ci			prefix = "";
274987da915Sopenharmony_ci			break;
275987da915Sopenharmony_ci	}
276987da915Sopenharmony_ci
277987da915Sopenharmony_ci	return prefix;
278987da915Sopenharmony_ci}
279987da915Sopenharmony_ci
280987da915Sopenharmony_ci
281987da915Sopenharmony_ci/**
282987da915Sopenharmony_ci * ntfs_log_set_handler - Provide an alternate logging handler
283987da915Sopenharmony_ci * @handler:	function to perform the logging
284987da915Sopenharmony_ci *
285987da915Sopenharmony_ci * This alternate handler will be called for all future logging requests.
286987da915Sopenharmony_ci * If no @handler is specified, logging will revert to the default handler.
287987da915Sopenharmony_ci */
288987da915Sopenharmony_civoid ntfs_log_set_handler(ntfs_log_handler *handler)
289987da915Sopenharmony_ci{
290987da915Sopenharmony_ci	if (handler) {
291987da915Sopenharmony_ci		ntfs_log.handler = handler;
292987da915Sopenharmony_ci#ifdef HAVE_SYSLOG_H
293987da915Sopenharmony_ci		if (handler == ntfs_log_handler_syslog)
294987da915Sopenharmony_ci			openlog("ntfs-3g", LOG_PID, LOG_USER);
295987da915Sopenharmony_ci#endif
296987da915Sopenharmony_ci	} else
297987da915Sopenharmony_ci		ntfs_log.handler = ntfs_log_handler_null;
298987da915Sopenharmony_ci}
299987da915Sopenharmony_ci
300987da915Sopenharmony_ci/**
301987da915Sopenharmony_ci * ntfs_log_redirect - Pass on the request to the real handler
302987da915Sopenharmony_ci * @function:	Function in which the log line occurred
303987da915Sopenharmony_ci * @file:	File in which the log line occurred
304987da915Sopenharmony_ci * @line:	Line number on which the log line occurred
305987da915Sopenharmony_ci * @level:	Level at which the line is logged
306987da915Sopenharmony_ci * @data:	User specified data, possibly specific to a handler
307987da915Sopenharmony_ci * @format:	printf-style formatting string
308987da915Sopenharmony_ci * @...:	Arguments to be formatted
309987da915Sopenharmony_ci *
310987da915Sopenharmony_ci * This is just a redirector function.  The arguments are simply passed to the
311987da915Sopenharmony_ci * main logging handler (as defined in the global logging struct @ntfs_log).
312987da915Sopenharmony_ci *
313987da915Sopenharmony_ci * Returns:  -1  Error occurred
314987da915Sopenharmony_ci *            0  Message wasn't logged
315987da915Sopenharmony_ci *          num  Number of output characters
316987da915Sopenharmony_ci */
317987da915Sopenharmony_ciint ntfs_log_redirect(const char *function, const char *file,
318987da915Sopenharmony_ci	int line, u32 level, void *data, const char *format, ...)
319987da915Sopenharmony_ci{
320987da915Sopenharmony_ci	int olderr = errno;
321987da915Sopenharmony_ci	int ret;
322987da915Sopenharmony_ci	va_list args;
323987da915Sopenharmony_ci
324987da915Sopenharmony_ci	if (!(ntfs_log.levels & level))		/* Don't log this message */
325987da915Sopenharmony_ci		return 0;
326987da915Sopenharmony_ci
327987da915Sopenharmony_ci	va_start(args, format);
328987da915Sopenharmony_ci	errno = olderr;
329987da915Sopenharmony_ci	ret = ntfs_log.handler(function, file, line, level, data, format, args);
330987da915Sopenharmony_ci	va_end(args);
331987da915Sopenharmony_ci
332987da915Sopenharmony_ci	errno = olderr;
333987da915Sopenharmony_ci	return ret;
334987da915Sopenharmony_ci}
335987da915Sopenharmony_ci
336987da915Sopenharmony_ci
337987da915Sopenharmony_ci/**
338987da915Sopenharmony_ci * ntfs_log_handler_syslog - syslog logging handler
339987da915Sopenharmony_ci * @function:	Function in which the log line occurred
340987da915Sopenharmony_ci * @file:	File in which the log line occurred
341987da915Sopenharmony_ci * @line:	Line number on which the log line occurred
342987da915Sopenharmony_ci * @level:	Level at which the line is logged
343987da915Sopenharmony_ci * @data:	User specified data, possibly specific to a handler
344987da915Sopenharmony_ci * @format:	printf-style formatting string
345987da915Sopenharmony_ci * @args:	Arguments to be formatted
346987da915Sopenharmony_ci *
347987da915Sopenharmony_ci * A simple syslog logging handler.  Ignores colors.
348987da915Sopenharmony_ci *
349987da915Sopenharmony_ci * Returns:  -1  Error occurred
350987da915Sopenharmony_ci *            0  Message wasn't logged
351987da915Sopenharmony_ci *          num  Number of output characters
352987da915Sopenharmony_ci */
353987da915Sopenharmony_ci
354987da915Sopenharmony_ci
355987da915Sopenharmony_ci#ifdef HAVE_SYSLOG_H
356987da915Sopenharmony_ci
357987da915Sopenharmony_ci#define LOG_LINE_LEN 	512
358987da915Sopenharmony_ci
359987da915Sopenharmony_ciint ntfs_log_handler_syslog(const char *function  __attribute__((unused)),
360987da915Sopenharmony_ci			    const char *file __attribute__((unused)),
361987da915Sopenharmony_ci			    int line __attribute__((unused)), u32 level,
362987da915Sopenharmony_ci			    void *data __attribute__((unused)),
363987da915Sopenharmony_ci			    const char *format, va_list args)
364987da915Sopenharmony_ci{
365987da915Sopenharmony_ci	char logbuf[LOG_LINE_LEN];
366987da915Sopenharmony_ci	int ret, olderr = errno;
367987da915Sopenharmony_ci
368987da915Sopenharmony_ci#ifndef DEBUG
369987da915Sopenharmony_ci	if ((level & NTFS_LOG_LEVEL_PERROR) && errno == ENOSPC)
370987da915Sopenharmony_ci		return 1;
371987da915Sopenharmony_ci#endif
372987da915Sopenharmony_ci	ret = vsnprintf(logbuf, LOG_LINE_LEN, format, args);
373987da915Sopenharmony_ci	if (ret < 0) {
374987da915Sopenharmony_ci		vsyslog(LOG_NOTICE, format, args);
375987da915Sopenharmony_ci		ret = 1;
376987da915Sopenharmony_ci		goto out;
377987da915Sopenharmony_ci	}
378987da915Sopenharmony_ci
379987da915Sopenharmony_ci	if ((LOG_LINE_LEN > ret + 3) && (level & NTFS_LOG_LEVEL_PERROR)) {
380987da915Sopenharmony_ci		strncat(logbuf, ": ", LOG_LINE_LEN - ret - 1);
381987da915Sopenharmony_ci		strncat(logbuf, strerror(olderr), LOG_LINE_LEN - (ret + 3));
382987da915Sopenharmony_ci		ret = strlen(logbuf);
383987da915Sopenharmony_ci	}
384987da915Sopenharmony_ci
385987da915Sopenharmony_ci	syslog(LOG_NOTICE, "%s", logbuf);
386987da915Sopenharmony_ciout:
387987da915Sopenharmony_ci	errno = olderr;
388987da915Sopenharmony_ci	return ret;
389987da915Sopenharmony_ci}
390987da915Sopenharmony_ci#endif
391987da915Sopenharmony_ci
392987da915Sopenharmony_ci/*
393987da915Sopenharmony_ci *			Early logging before the logs are redirected
394987da915Sopenharmony_ci *
395987da915Sopenharmony_ci *	(not quite satisfactory : this appears before the ntfs-g banner,
396987da915Sopenharmony_ci *	and with a different pid)
397987da915Sopenharmony_ci */
398987da915Sopenharmony_ci
399987da915Sopenharmony_civoid ntfs_log_early_error(const char *format, ...)
400987da915Sopenharmony_ci{
401987da915Sopenharmony_ci	va_list args;
402987da915Sopenharmony_ci
403987da915Sopenharmony_ci	va_start(args, format);
404987da915Sopenharmony_ci#ifdef HAVE_SYSLOG_H
405987da915Sopenharmony_ci	openlog("ntfs-3g", LOG_PID, LOG_USER);
406987da915Sopenharmony_ci	ntfs_log_handler_syslog(NULL, NULL, 0,
407987da915Sopenharmony_ci		NTFS_LOG_LEVEL_ERROR, NULL,
408987da915Sopenharmony_ci		format, args);
409987da915Sopenharmony_ci#else
410987da915Sopenharmony_ci	vfprintf(stderr,format,args);
411987da915Sopenharmony_ci#endif
412987da915Sopenharmony_ci	va_end(args);
413987da915Sopenharmony_ci}
414987da915Sopenharmony_ci
415987da915Sopenharmony_ci/**
416987da915Sopenharmony_ci * ntfs_log_handler_fprintf - Basic logging handler
417987da915Sopenharmony_ci * @function:	Function in which the log line occurred
418987da915Sopenharmony_ci * @file:	File in which the log line occurred
419987da915Sopenharmony_ci * @line:	Line number on which the log line occurred
420987da915Sopenharmony_ci * @level:	Level at which the line is logged
421987da915Sopenharmony_ci * @data:	User specified data, possibly specific to a handler
422987da915Sopenharmony_ci * @format:	printf-style formatting string
423987da915Sopenharmony_ci * @args:	Arguments to be formatted
424987da915Sopenharmony_ci *
425987da915Sopenharmony_ci * A simple logging handler.  This is where the log line is finally displayed.
426987da915Sopenharmony_ci * It is more likely that you will want to set the handler to either
427987da915Sopenharmony_ci * ntfs_log_handler_outerr or ntfs_log_handler_stderr.
428987da915Sopenharmony_ci *
429987da915Sopenharmony_ci * Note: For this handler, @data is a pointer to a FILE output stream.
430987da915Sopenharmony_ci *       If @data is NULL, nothing will be displayed.
431987da915Sopenharmony_ci *
432987da915Sopenharmony_ci * Returns:  -1  Error occurred
433987da915Sopenharmony_ci *            0  Message wasn't logged
434987da915Sopenharmony_ci *          num  Number of output characters
435987da915Sopenharmony_ci */
436987da915Sopenharmony_ciint ntfs_log_handler_fprintf(const char *function, const char *file,
437987da915Sopenharmony_ci	int line, u32 level, void *data, const char *format, va_list args)
438987da915Sopenharmony_ci{
439987da915Sopenharmony_ci#ifdef DEBUG
440987da915Sopenharmony_ci	int i;
441987da915Sopenharmony_ci#endif
442987da915Sopenharmony_ci	int ret = 0;
443987da915Sopenharmony_ci	int olderr = errno;
444987da915Sopenharmony_ci	FILE *stream;
445987da915Sopenharmony_ci
446987da915Sopenharmony_ci	if (!data)		/* Interpret data as a FILE stream. */
447987da915Sopenharmony_ci		return 0;	/* If it's NULL, we can't do anything. */
448987da915Sopenharmony_ci	stream = (FILE*)data;
449987da915Sopenharmony_ci
450987da915Sopenharmony_ci#ifdef DEBUG
451987da915Sopenharmony_ci	if (level == NTFS_LOG_LEVEL_LEAVE) {
452987da915Sopenharmony_ci		if (tab)
453987da915Sopenharmony_ci			tab--;
454987da915Sopenharmony_ci		return 0;
455987da915Sopenharmony_ci	}
456987da915Sopenharmony_ci
457987da915Sopenharmony_ci	for (i = 0; i < tab; i++)
458987da915Sopenharmony_ci		ret += fprintf(stream, " ");
459987da915Sopenharmony_ci#endif
460987da915Sopenharmony_ci	if ((ntfs_log.flags & NTFS_LOG_FLAG_ONLYNAME) &&
461987da915Sopenharmony_ci	    (strchr(file, PATH_SEP)))		/* Abbreviate the filename */
462987da915Sopenharmony_ci		file = strrchr(file, PATH_SEP) + 1;
463987da915Sopenharmony_ci
464987da915Sopenharmony_ci	if (ntfs_log.flags & NTFS_LOG_FLAG_PREFIX)	/* Prefix the output */
465987da915Sopenharmony_ci		ret += fprintf(stream, "%s", ntfs_log_get_prefix(level));
466987da915Sopenharmony_ci
467987da915Sopenharmony_ci	if (ntfs_log.flags & NTFS_LOG_FLAG_FILENAME)	/* Source filename */
468987da915Sopenharmony_ci		ret += fprintf(stream, "%s ", file);
469987da915Sopenharmony_ci
470987da915Sopenharmony_ci	if (ntfs_log.flags & NTFS_LOG_FLAG_LINE)	/* Source line number */
471987da915Sopenharmony_ci		ret += fprintf(stream, "(%d) ", line);
472987da915Sopenharmony_ci
473987da915Sopenharmony_ci	if ((ntfs_log.flags & NTFS_LOG_FLAG_FUNCTION) || /* Source function */
474987da915Sopenharmony_ci	    (level & NTFS_LOG_LEVEL_TRACE) || (level & NTFS_LOG_LEVEL_ENTER))
475987da915Sopenharmony_ci		ret += fprintf(stream, "%s(): ", function);
476987da915Sopenharmony_ci
477987da915Sopenharmony_ci	ret += vfprintf(stream, format, args);
478987da915Sopenharmony_ci
479987da915Sopenharmony_ci	if (level & NTFS_LOG_LEVEL_PERROR)
480987da915Sopenharmony_ci		ret += fprintf(stream, ": %s\n", strerror(olderr));
481987da915Sopenharmony_ci
482987da915Sopenharmony_ci#ifdef DEBUG
483987da915Sopenharmony_ci	if (level == NTFS_LOG_LEVEL_ENTER)
484987da915Sopenharmony_ci		tab++;
485987da915Sopenharmony_ci#endif
486987da915Sopenharmony_ci	fflush(stream);
487987da915Sopenharmony_ci	errno = olderr;
488987da915Sopenharmony_ci	return ret;
489987da915Sopenharmony_ci}
490987da915Sopenharmony_ci
491987da915Sopenharmony_ci/**
492987da915Sopenharmony_ci * ntfs_log_handler_null - Null logging handler (no output)
493987da915Sopenharmony_ci * @function:	Function in which the log line occurred
494987da915Sopenharmony_ci * @file:	File in which the log line occurred
495987da915Sopenharmony_ci * @line:	Line number on which the log line occurred
496987da915Sopenharmony_ci * @level:	Level at which the line is logged
497987da915Sopenharmony_ci * @data:	User specified data, possibly specific to a handler
498987da915Sopenharmony_ci * @format:	printf-style formatting string
499987da915Sopenharmony_ci * @args:	Arguments to be formatted
500987da915Sopenharmony_ci *
501987da915Sopenharmony_ci * This handler produces no output.  It provides a way to temporarily disable
502987da915Sopenharmony_ci * logging, without having to change the levels and flags.
503987da915Sopenharmony_ci *
504987da915Sopenharmony_ci * Returns:  0  Message wasn't logged
505987da915Sopenharmony_ci */
506987da915Sopenharmony_ciint ntfs_log_handler_null(const char *function __attribute__((unused)), const char *file __attribute__((unused)),
507987da915Sopenharmony_ci	int line __attribute__((unused)), u32 level __attribute__((unused)), void *data __attribute__((unused)),
508987da915Sopenharmony_ci	const char *format __attribute__((unused)), va_list args __attribute__((unused)))
509987da915Sopenharmony_ci{
510987da915Sopenharmony_ci	return 0;
511987da915Sopenharmony_ci}
512987da915Sopenharmony_ci
513987da915Sopenharmony_ci/**
514987da915Sopenharmony_ci * ntfs_log_handler_stdout - All logs go to stdout
515987da915Sopenharmony_ci * @function:	Function in which the log line occurred
516987da915Sopenharmony_ci * @file:	File in which the log line occurred
517987da915Sopenharmony_ci * @line:	Line number on which the log line occurred
518987da915Sopenharmony_ci * @level:	Level at which the line is logged
519987da915Sopenharmony_ci * @data:	User specified data, possibly specific to a handler
520987da915Sopenharmony_ci * @format:	printf-style formatting string
521987da915Sopenharmony_ci * @args:	Arguments to be formatted
522987da915Sopenharmony_ci *
523987da915Sopenharmony_ci * Display a log message to stdout.
524987da915Sopenharmony_ci *
525987da915Sopenharmony_ci * Note: For this handler, @data is a pointer to a FILE output stream.
526987da915Sopenharmony_ci *       If @data is NULL, then stdout will be used.
527987da915Sopenharmony_ci *
528987da915Sopenharmony_ci * Note: This function calls ntfs_log_handler_fprintf to do the main work.
529987da915Sopenharmony_ci *
530987da915Sopenharmony_ci * Returns:  -1  Error occurred
531987da915Sopenharmony_ci *            0  Message wasn't logged
532987da915Sopenharmony_ci *          num  Number of output characters
533987da915Sopenharmony_ci */
534987da915Sopenharmony_ciint ntfs_log_handler_stdout(const char *function, const char *file,
535987da915Sopenharmony_ci	int line, u32 level, void *data, const char *format, va_list args)
536987da915Sopenharmony_ci{
537987da915Sopenharmony_ci	if (!data)
538987da915Sopenharmony_ci		data = stdout;
539987da915Sopenharmony_ci
540987da915Sopenharmony_ci	return ntfs_log_handler_fprintf(function, file, line, level, data, format, args);
541987da915Sopenharmony_ci}
542987da915Sopenharmony_ci
543987da915Sopenharmony_ci/**
544987da915Sopenharmony_ci * ntfs_log_handler_outerr - Logs go to stdout/stderr depending on level
545987da915Sopenharmony_ci * @function:	Function in which the log line occurred
546987da915Sopenharmony_ci * @file:	File in which the log line occurred
547987da915Sopenharmony_ci * @line:	Line number on which the log line occurred
548987da915Sopenharmony_ci * @level:	Level at which the line is logged
549987da915Sopenharmony_ci * @data:	User specified data, possibly specific to a handler
550987da915Sopenharmony_ci * @format:	printf-style formatting string
551987da915Sopenharmony_ci * @args:	Arguments to be formatted
552987da915Sopenharmony_ci *
553987da915Sopenharmony_ci * Display a log message.  The output stream will be determined by the log
554987da915Sopenharmony_ci * level.
555987da915Sopenharmony_ci *
556987da915Sopenharmony_ci * Note: For this handler, @data is a pointer to a FILE output stream.
557987da915Sopenharmony_ci *       If @data is NULL, the function ntfs_log_get_stream will be called
558987da915Sopenharmony_ci *
559987da915Sopenharmony_ci * Note: This function calls ntfs_log_handler_fprintf to do the main work.
560987da915Sopenharmony_ci *
561987da915Sopenharmony_ci * Returns:  -1  Error occurred
562987da915Sopenharmony_ci *            0  Message wasn't logged
563987da915Sopenharmony_ci *          num  Number of output characters
564987da915Sopenharmony_ci */
565987da915Sopenharmony_ciint ntfs_log_handler_outerr(const char *function, const char *file,
566987da915Sopenharmony_ci	int line, u32 level, void *data, const char *format, va_list args)
567987da915Sopenharmony_ci{
568987da915Sopenharmony_ci	if (!data)
569987da915Sopenharmony_ci		data = ntfs_log_get_stream(level);
570987da915Sopenharmony_ci
571987da915Sopenharmony_ci	return ntfs_log_handler_fprintf(function, file, line, level, data, format, args);
572987da915Sopenharmony_ci}
573987da915Sopenharmony_ci
574987da915Sopenharmony_ci/**
575987da915Sopenharmony_ci * ntfs_log_handler_stderr - All logs go to stderr
576987da915Sopenharmony_ci * @function:	Function in which the log line occurred
577987da915Sopenharmony_ci * @file:	File in which the log line occurred
578987da915Sopenharmony_ci * @line:	Line number on which the log line occurred
579987da915Sopenharmony_ci * @level:	Level at which the line is logged
580987da915Sopenharmony_ci * @data:	User specified data, possibly specific to a handler
581987da915Sopenharmony_ci * @format:	printf-style formatting string
582987da915Sopenharmony_ci * @args:	Arguments to be formatted
583987da915Sopenharmony_ci *
584987da915Sopenharmony_ci * Display a log message to stderr.
585987da915Sopenharmony_ci *
586987da915Sopenharmony_ci * Note: For this handler, @data is a pointer to a FILE output stream.
587987da915Sopenharmony_ci *       If @data is NULL, then stdout will be used.
588987da915Sopenharmony_ci *
589987da915Sopenharmony_ci * Note: This function calls ntfs_log_handler_fprintf to do the main work.
590987da915Sopenharmony_ci *
591987da915Sopenharmony_ci * Returns:  -1  Error occurred
592987da915Sopenharmony_ci *            0  Message wasn't logged
593987da915Sopenharmony_ci *          num  Number of output characters
594987da915Sopenharmony_ci */
595987da915Sopenharmony_ciint ntfs_log_handler_stderr(const char *function, const char *file,
596987da915Sopenharmony_ci	int line, u32 level, void *data, const char *format, va_list args)
597987da915Sopenharmony_ci{
598987da915Sopenharmony_ci	if (!data)
599987da915Sopenharmony_ci		data = stderr;
600987da915Sopenharmony_ci
601987da915Sopenharmony_ci	return ntfs_log_handler_fprintf(function, file, line, level, data, format, args);
602987da915Sopenharmony_ci}
603987da915Sopenharmony_ci
604987da915Sopenharmony_ci
605987da915Sopenharmony_ci/**
606987da915Sopenharmony_ci * ntfs_log_parse_option - Act upon command line options
607987da915Sopenharmony_ci * @option:	Option flag
608987da915Sopenharmony_ci *
609987da915Sopenharmony_ci * Delegate some of the work of parsing the command line.  All the options begin
610987da915Sopenharmony_ci * with "--log-".  Options cause log levels to be enabled in @ntfs_log (the
611987da915Sopenharmony_ci * global logging structure).
612987da915Sopenharmony_ci *
613987da915Sopenharmony_ci * Note: The "colour" option changes the logging handler.
614987da915Sopenharmony_ci *
615987da915Sopenharmony_ci * Returns:  TRUE  Option understood
616987da915Sopenharmony_ci *          FALSE  Invalid log option
617987da915Sopenharmony_ci */
618987da915Sopenharmony_ciBOOL ntfs_log_parse_option(const char *option)
619987da915Sopenharmony_ci{
620987da915Sopenharmony_ci	if (strcmp(option, "--log-debug") == 0) {
621987da915Sopenharmony_ci		ntfs_log_set_levels(NTFS_LOG_LEVEL_DEBUG);
622987da915Sopenharmony_ci		return TRUE;
623987da915Sopenharmony_ci	} else if (strcmp(option, "--log-verbose") == 0) {
624987da915Sopenharmony_ci		ntfs_log_set_levels(NTFS_LOG_LEVEL_VERBOSE);
625987da915Sopenharmony_ci		return TRUE;
626987da915Sopenharmony_ci	} else if (strcmp(option, "--log-quiet") == 0) {
627987da915Sopenharmony_ci		ntfs_log_clear_levels(NTFS_LOG_LEVEL_QUIET);
628987da915Sopenharmony_ci		return TRUE;
629987da915Sopenharmony_ci	} else if (strcmp(option, "--log-trace") == 0) {
630987da915Sopenharmony_ci		ntfs_log_set_levels(NTFS_LOG_LEVEL_TRACE);
631987da915Sopenharmony_ci		return TRUE;
632987da915Sopenharmony_ci	}
633987da915Sopenharmony_ci
634987da915Sopenharmony_ci	ntfs_log_debug("Unknown logging option '%s'\n", option);
635987da915Sopenharmony_ci	return FALSE;
636987da915Sopenharmony_ci}
637987da915Sopenharmony_ci
638