1    	/*
2    	 * vim:noexpandtab:shiftwidth=8:tabstop=8:
3    	 *
4    	 * Copyright CEA/DAM/DIF  (2008)
5    	 * contributeur : Philippe DENIEL   philippe.deniel@cea.fr
6    	 *                Thomas LEIBOVICI  thomas.leibovici@cea.fr
7    	 *
8    	 *
9    	 * This program is free software; you can redistribute it and/or
10   	 * modify it under the terms of the GNU Lesser General Public
11   	 * License as published by the Free Software Foundation; either
12   	 * version 3 of the License, or (at your option) any later version.
13   	 *
14   	 * This program is distributed in the hope that it will be useful,
15   	 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   	 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17   	 * Lesser General Public License for more details.
18   	 *
19   	 * You should have received a copy of the GNU Lesser General Public
20   	 * License along with this library; if not, write to the Free Software
21   	 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
22   	 *
23   	 * ---------------------------------------
24   	 *
25   	 * All the display functions and error handling.
26   	 *
27   	 */
28   	#include "config.h"
29   	
30   	#include <pthread.h>
31   	#include <stdio.h>
32   	#include <stdarg.h>
33   	#include <unistd.h>
34   	#include <fcntl.h>
35   	#include <time.h>
36   	#include <sys/types.h>
37   	#include <sys/param.h>
38   	#include <sys/stat.h>
39   	#include <errno.h>
40   	#include <string.h>
41   	#include <signal.h>
42   	#include <libgen.h>
43   	#include <sys/resource.h>
44   	#include <execinfo.h>
45   	
46   	#include "log.h"
47   	#include "gsh_list.h"
48   	#include "gsh_rpc.h"
49   	#include "common_utils.h"
50   	#include "abstract_mem.h"
51   	
52   	#ifdef USE_DBUS
53   	#include "gsh_dbus.h"
54   	#endif
55   	
56   	#include "nfs_core.h"
57   	#include "config_parsing.h"
58   	
59   	#ifdef USE_LTTNG
60   	#include "gsh_lttng/logger.h"
61   	#endif
62   	
63   	/*
64   	 * The usual PTHREAD_RWLOCK_xxx macros log messages for tracing if FULL
65   	 * DEBUG is enabled. If such a macro is called from this logging file as
66   	 * part of logging a message, it generates endless loop of lock tracing
67   	 * messages. The following code redefines these lock macros to avoid the
68   	 * loop.
69   	 */
70   	#ifdef PTHREAD_RWLOCK_wrlock
71   	#undef PTHREAD_RWLOCK_wrlock
72   	#endif
73   	#define PTHREAD_RWLOCK_wrlock(_lock)					\
74   		do {								\
75   			if (pthread_rwlock_wrlock(_lock) != 0)			\
76   				assert(0);					\
77   		} while (0)
78   	
79   	#ifdef PTHREAD_RWLOCK_rdlock
80   	#undef PTHREAD_RWLOCK_rdlock
81   	#endif
82   	#define PTHREAD_RWLOCK_rdlock(_lock)					\
83   		do {								\
84   			if (pthread_rwlock_rdlock(_lock) != 0)			\
85   				assert(0);					\
86   		} while (0)
87   	
88   	#ifdef PTHREAD_RWLOCK_unlock
89   	#undef PTHREAD_RWLOCK_unlock
90   	#endif
91   	#define PTHREAD_RWLOCK_unlock(_lock)					\
92   		do {								\
93   			if (pthread_rwlock_unlock(_lock) != 0)			\
94   				assert(0);					\
95   		} while (0)
96   	
97   	pthread_rwlock_t log_rwlock = PTHREAD_RWLOCK_INITIALIZER;
98   	
99   	/* Variables to control log fields */
100  	
101  	/**
102  	 * @brief Define an index each of the log fields that are configurable.
103  	 *
104  	 * Ganesha log messages have several "header" fields used in every
105  	 * message. Some of those fields may be configured (mostly display or
106  	 * not display).
107  	 *
108  	 */
109  	enum log_flag_index_t {
110  		LF_DATE,		/*< Date field. */
111  		LF_TIME,		/*< Time field. */
112  		LF_EPOCH,		/*< Server Epoch field (distinguishes server
113  					    instance. */
114  		LF_CLIENTIP,            /* <Client IP field. */
115  		LF_HOSTAME,		/*< Server host name field. */
116  		LF_PROGNAME,		/*< Ganesha program name field. */
117  		LF_PID,			/*< Ganesha process identifier. */
118  		LF_THREAD_NAME,		/*< Name of active thread logging message. */
119  		LF_FILE_NAME,		/*< Source file name message occured in. */
120  		LF_LINE_NUM,		/*< Source line number message occurred in. */
121  		LF_FUNCTION_NAME,	/*< Function name message occurred in. */
122  		LF_COMPONENT,		/*< Log component. */
123  		LF_LEVEL,		/*< Log level. */
124  	};
125  	
126  	/**
127  	 * @brief Define a set of possible time and date formats.
128  	 *
129  	 * These values will be stored in lf_ext for the LF_DATE and LF_TIME flags.
130  	 *
131  	 */
132  	enum timedate_formats_t {
133  		TD_NONE,		/*< No time/date. */
134  		TD_GANESHA,		/*< Legacy Ganesha time and date format. */
135  		TD_LOCAL,		/*< Use strftime local format for time/date. */
136  		TD_8601,		/*< Use ISO 8601 time/date format. */
137  		TD_SYSLOG,		/*< Use a typical syslog time/date format. */
138  		TD_SYSLOG_USEC,		/*< Use a typical syslog time/date format that
139  					    also includes microseconds. */
140  		TD_USER,		/* Use a user defined time/date format. */
141  	};
142  	
143  	/**
144  	 * @brief Format control for log messages
145  	 *
146  	 */
147  	
148  	struct logfields {
149  		bool disp_epoch;
150  		bool disp_clientip;
151  		bool disp_host;
152  		bool disp_prog;
153  		bool disp_pid;
154  		bool disp_threadname;
155  		bool disp_filename;
156  		bool disp_linenum;
157  		bool disp_funct;
158  		bool disp_comp;
159  		bool disp_level;
160  		enum timedate_formats_t datefmt;
161  		enum timedate_formats_t timefmt;
162  		char *user_date_fmt;
163  		char *user_time_fmt;
164  	};
165  	
166  	/**
167  	 * @brief Startup default log message format
168  	 *
169  	 * Baked in here so early startup has something to work with
170  	 */
171  	
172  	static struct logfields default_logfields = {
173  		.disp_epoch = true,
174  		.disp_host = true,
175  		.disp_prog = true,
176  		.disp_pid = true,
177  		.disp_threadname = true,
178  		.disp_filename = false,
179  		.disp_linenum = false,
180  		.disp_funct = true,
181  		.disp_comp = true,
182  		.disp_level = true,
183  		.datefmt = TD_GANESHA,
184  		.timefmt = TD_GANESHA
185  	};
186  	
187  	static struct logfields *logfields = &default_logfields;
188  	
189  	/**
190  	 * @brief Define the structure for a log facility.
191  	 *
192  	 */
193  	struct log_facility {
194  		struct glist_head lf_list;	/*< List of log facilities */
195  		struct glist_head lf_active;	/*< This is an active facility */
196  		char *lf_name;			/*< Name of log facility */
197  		log_levels_t lf_max_level;	/*< Max log level for this facility */
198  		log_header_t lf_headers;	/*< If time stamp etc. are part of msg
199  						 */
200  		lf_function_t *lf_func;	/*< Function that describes facility   */
201  		void *lf_private;	/*< Private info for facility          */
202  	};
203  	
204  	/* Define the maximum length of a user time/date format. */
205  	#define MAX_TD_USER_LEN 64
206  	/* Define the maximum overall time/date format length, should have room
207  	 * for both user date and user time format plus room for blanks around them.
208  	 */
209  	#define MAX_TD_FMT_LEN (MAX_TD_USER_LEN * 2 + 4)
210  	
211  	static int log_to_syslog(log_header_t headers, void *private,
212  				 log_levels_t level,
213  				 struct display_buffer *buffer, char *compstr,
214  				 char *message);
215  	
216  	static int log_to_file(log_header_t headers, void *private,
217  			       log_levels_t level,
218  			       struct display_buffer *buffer, char *compstr,
219  			       char *message);
220  	
221  	static int log_to_stream(log_header_t headers, void *private,
222  				 log_levels_t level,
223  				 struct display_buffer *buffer, char *compstr,
224  				 char *message);
225  	
226  	static struct glist_head facility_list;
227  	static struct glist_head active_facility_list;
228  	
229  	static struct log_facility *default_facility;
230  	
231  	log_header_t max_headers = LH_COMPONENT;
232  	
233  	char const_log_str[LOG_BUFF_LEN] = "\0";
234  	char date_time_fmt[MAX_TD_FMT_LEN] = "\0";
235  	
236  	typedef struct loglev {
237  		char *str;
238  		char *short_str;
239  		int syslog_level;
240  	} log_level_t;
241  	
242  	static log_level_t tabLogLevel[] = {
243  		[NIV_NULL] = {"NIV_NULL", "NULL", LOG_NOTICE},
244  		[NIV_FATAL] = {"NIV_FATAL", "FATAL", LOG_CRIT},
245  		[NIV_MAJ] = {"NIV_MAJ", "MAJ", LOG_CRIT},
246  		[NIV_CRIT] = {"NIV_CRIT", "CRIT", LOG_ERR},
247  		[NIV_WARN] = {"NIV_WARN", "WARN", LOG_WARNING},
248  		[NIV_EVENT] = {"NIV_EVENT", "EVENT", LOG_NOTICE},
249  		[NIV_INFO] = {"NIV_INFO", "INFO", LOG_INFO},
250  		[NIV_DEBUG] = {"NIV_DEBUG", "DEBUG", LOG_DEBUG},
251  		[NIV_MID_DEBUG] = {"NIV_MID_DEBUG", "M_DBG", LOG_DEBUG},
252  		[NIV_FULL_DEBUG] = {"NIV_FULL_DEBUG", "F_DBG", LOG_DEBUG}
253  	};
254  	
255  	#ifndef ARRAY_SIZE
256  	#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
257  	#endif
258  	
259  	/* constants */
260  	static int log_mask = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
261  	
262  	/* Global variables */
263  	
264  	static char program_name[1024];
265  	static char hostname[256];
266  	static int syslog_opened;
267  	
268  	/*
269  	 * Variables specifiques aux threads.
270  	 */
271  	
272  	__thread char thread_name[32];
273  	__thread char log_buffer[LOG_BUFF_LEN + 1];
274  	__thread char *clientip = NULL;
275  	
276  	/* threads keys */
277  	#define LogChanges(format, args...) \
278  		do { \
279  			if (component_log_level[COMPONENT_LOG] == \
280  			    NIV_FULL_DEBUG) \
281  				DisplayLogComponentLevel(COMPONENT_LOG, \
282  							 __FILE__, \
283  							 __LINE__, \
284  							 __func__, \
285  							 NIV_NULL, \
286  							 "LOG: " format, \
287  							 ## args); \
288  		} while (0)
289  	
290  	struct cleanup_list_element *cleanup_list;
291  	
292  	void RegisterCleanup(struct cleanup_list_element *clean)
293  	{
294  		clean->next = cleanup_list;
295  		cleanup_list = clean;
296  	}
297  	
298  	void Cleanup(void)
299  	{
300  		struct cleanup_list_element *c = cleanup_list;
301  	
302  		while (c != NULL) {
303  			c->clean();
304  			c = c->next;
305  		}
306  	}
307  	
308  	void Fatal(void)
309  	{
310  		Cleanup();
311  		exit(2);
312  	}
313  	
314  	#ifdef _DONT_HAVE_LOCALTIME_R
315  	
316  	/* Localtime is not reentrant...
317  	 * So we are obliged to have a mutex for calling it.
318  	 * pffff....
319  	 */
320  	static pthread_mutex_t mutex_localtime = PTHREAD_MUTEX_INITIALIZER;
321  	
322  	/* thread-safe and PORTABLE version of localtime */
323  	
324  	static struct tm *Localtime_r(const time_t *p_time, struct tm *p_tm)
325  	{
326  		struct tm *p_tmp_tm;
327  	
328  		if (!p_tm) {
329  			errno = EFAULT;
330  			return NULL;
331  		}
332  	
333  		PTHREAD_MUTEX_lock(&mutex_localtime);
334  	
335  		p_tmp_tm = localtime(p_time);
336  	
337  		/* copy the result */
338  		(*p_tm) = (*p_tmp_tm);
339  	
340  		PTHREAD_MUTEX_unlock(&mutex_localtime);
341  	
342  		return p_tm;
343  	}
344  	#else
345  	#define Localtime_r localtime_r
346  	#endif
347  	
348  	/*
349  	 * Convert a numeral log level in ascii to
350  	 * the numeral value.
351  	 */
352  	int ReturnLevelAscii(const char *LevelInAscii)
353  	{
354  		int i = 0;
355  	
356  		for (i = 0; i < ARRAY_SIZE(tabLogLevel); i++)
357  			if (tabLogLevel[i].str != NULL &&
358  			    (!strcasecmp(tabLogLevel[i].str, LevelInAscii)
359  			     || !strcasecmp(tabLogLevel[i].str + 4, LevelInAscii)
360  			     || !strcasecmp(tabLogLevel[i].short_str, LevelInAscii)))
361  				return i;
362  	
363  		/* If nothing found, return -1 */
364  		return -1;
365  	}				/* ReturnLevelAscii */
366  	
367  	char *ReturnLevelInt(int level)
368  	{
369  		if (level >= 0 && level < NB_LOG_LEVEL)
370  			return tabLogLevel[level].str;
371  	
372  		/* If nothing is found, return NULL. */
373  		return NULL;
374  	}				/* ReturnLevelInt */
375  	
376  	/*
377  	 * Set the name of this program.
378  	 */
379  	void SetNamePgm(const char *nom)
380  	{
381  	
382  		/* This function isn't thread-safe because the name of the program
383  		 * is common among all the threads. */
384  		if (strmaxcpy(program_name, nom, sizeof(program_name)) == -1)
385  			LogFatal(COMPONENT_LOG, "Program name %s too long", nom);
386  	}				/* SetNamePgm */
387  	
388  	/*
389  	 * Set the hostname.
390  	 */
391  	void SetNameHost(const char *name)
392  	{
393  		if (strmaxcpy(hostname, name, sizeof(hostname)) == -1)
394  			LogFatal(COMPONENT_LOG, "Host name %s too long", name);
395  	}				/* SetNameHost */
396  	
397  	/* Set the function name in progress. */
398  	void SetNameFunction(const char *nom)
399  	{
400  		strlcpy(thread_name, nom, sizeof(thread_name));
401  		if (strlen(nom) >= sizeof(thread_name))
402  			LogWarn(COMPONENT_LOG,
403  				"Thread name %s too long truncated to %s",
404  				nom, thread_name);
405  		clientip = NULL;
406  	}
407  	
408  	/*
409  	 * Sets the IP of the Client for this thread.
410  	 * Make sure ip_str is valid for the duration of the thread
411  	 */
412  	void SetClientIP(char *ip_str)
413  	{
414  		clientip = ip_str;
415  	}
416  	
417  	/* Installs a signal handler */
418  	static void ArmSignal(int signal, void (*action) ())
419  	{
420  		struct sigaction act;
421  	
422  		/* Placing fields of struct sigaction */
423  		act.sa_flags = 0;
424  		act.sa_handler = action;
425  		sigemptyset(&act.sa_mask);
426  	
427  		if (sigaction(signal, &act, NULL) == -1)
428  			LogCrit(COMPONENT_LOG, "Failed to arm signal %d, error %d (%s)",
429  				signal, errno, strerror(errno));
430  	}				/* ArmSignal */
431  	
432  	/*
433  	 * Five functions to manage debug level throug signal
434  	 * handlers.
435  	 *
436  	 * InitLogging
437  	 * IncrementLevelDebug
438  	 * DecrementLevelDebug
439  	 * SetLevelDebug
440  	 * ReturnLevelDebug
441  	 */
442  	
443  	static void _SetLevelDebug(int level_to_set)
444  	{
445  		int i;
446  	
447  		if (level_to_set < NIV_NULL)
448  			level_to_set = NIV_NULL;
449  	
450  		if (level_to_set >= NB_LOG_LEVEL)
451  			level_to_set = NB_LOG_LEVEL - 1;
452  	
453  		/* COMPONENT_ALL is a pseudo component, handle it separately */
454  		component_log_level[COMPONENT_ALL] = level_to_set;
455  		for (i = COMPONENT_ALL + 1; i < COMPONENT_COUNT; i++) {
456  			SetComponentLogLevel(i, level_to_set);
457  		}
458  	}				/* _SetLevelDebug */
459  	
460  	static void SetLevelDebug(int level_to_set)
461  	{
462  		_SetLevelDebug(level_to_set);
463  	
464  		LogChanges("Setting log level for all components to %s",
465  			   ReturnLevelInt(component_log_level[COMPONENT_ALL]));
466  	}
467  	
468  	static void SetNTIRPCLogLevel(int level_to_set)
469  	{
470  		switch (level_to_set) {
471  		case NIV_NULL:
472  		case NIV_FATAL:
473  			ntirpc_pp.debug_flags = 0; /* disable all flags */
474  			break;
475  		case NIV_CRIT:
476  		case NIV_MAJ:
477  			ntirpc_pp.debug_flags = TIRPC_DEBUG_FLAG_ERROR;
478  			break;
479  		case NIV_WARN:
480  			ntirpc_pp.debug_flags = TIRPC_DEBUG_FLAG_ERROR |
481  						TIRPC_DEBUG_FLAG_WARN;
482  			break;
483  		case NIV_EVENT:
484  			ntirpc_pp.debug_flags = TIRPC_DEBUG_FLAG_ERROR |
485  						TIRPC_DEBUG_FLAG_WARN |
486  						TIRPC_DEBUG_FLAG_EVENT;
487  			break;
488  		case NIV_DEBUG:
489  		case NIV_MID_DEBUG:
490  			/* set by log_conf_commit() */
491  			break;
492  		case NIV_FULL_DEBUG:
493  			ntirpc_pp.debug_flags = 0xFFFFFFFF; /* enable all flags */
494  			break;
495  		default:
496  			ntirpc_pp.debug_flags = TIRPC_DEBUG_FLAG_DEFAULT;
497  			break;
498  		}
499  	
500  		if (!tirpc_control(TIRPC_SET_DEBUG_FLAGS, &ntirpc_pp.debug_flags))
501  			LogCrit(COMPONENT_CONFIG, "Setting nTI-RPC debug_flags failed");
502  	}
503  	
504  	void SetComponentLogLevel(log_components_t component, int level_to_set)
505  	{
506  	
507  		assert(level_to_set >= NIV_NULL);
508  		assert(level_to_set < NB_LOG_LEVEL);
509  		assert(component != COMPONENT_ALL);
510  	
511  		if (LogComponents[component].comp_env_set) {
512  			LogWarn(COMPONENT_CONFIG,
513  				"LOG %s level %s from config is ignored because %s was set in environment",
514  				LogComponents[component].comp_name,
515  				ReturnLevelInt(level_to_set),
516  				ReturnLevelInt(component_log_level[component]));
517  			return;
518  		}
519  	
520  		if (component_log_level[component] == level_to_set)
521  			return;
522  	
523  		LogChanges("Changing log level of %s from %s to %s",
524  			   LogComponents[component].comp_name,
525  			   ReturnLevelInt(component_log_level[component]),
526  			   ReturnLevelInt(level_to_set));
527  		component_log_level[component] = level_to_set;
528  	
529  		if (component == COMPONENT_TIRPC)
530  			SetNTIRPCLogLevel(level_to_set);
531  	}
532  	
533  	static inline int ReturnLevelDebug(void)
534  	{
535  		return component_log_level[COMPONENT_ALL];
536  	}				/* ReturnLevelDebug */
537  	
538  	static void IncrementLevelDebug(void)
539  	{
540  		_SetLevelDebug(ReturnLevelDebug() + 1);
541  	
542  		LogChanges("SIGUSR1 Increasing log level for all components to %s",
543  			   ReturnLevelInt(component_log_level[COMPONENT_ALL]));
544  	}				/* IncrementLevelDebug */
545  	
546  	static void DecrementLevelDebug(void)
547  	{
548  		_SetLevelDebug(ReturnLevelDebug() - 1);
549  	
550  		LogChanges("SIGUSR2 Decreasing log level for all components to %s",
551  			   ReturnLevelInt(component_log_level[COMPONENT_ALL]));
552  	}				/* DecrementLevelDebug */
553  	
554  	void set_const_log_str(void)
555  	{
556  		struct display_buffer dspbuf = { sizeof(const_log_str),
557  			const_log_str,
558  			const_log_str
559  		};
560  		struct display_buffer tdfbuf = { sizeof(date_time_fmt),
561  			date_time_fmt,
562  			date_time_fmt
563  		};
564  		int b_left = display_start(&dspbuf);
565  	
566  		const_log_str[0] = '\0';
567  	
568  		if (b_left > 0 && logfields->disp_epoch)
569  			b_left = display_printf(&dspbuf,
(1) Event invalid_type: Argument "nfs_ServerEpoch" to format specifier "%08x" was expected to have type "unsigned int" but has type "long". [details]
570  				": epoch %08x ", nfs_ServerEpoch);
571  	
572  		if (b_left > 0 && logfields->disp_host)
573  			b_left = display_printf(&dspbuf, ": %s ", hostname);
574  	
575  		if (b_left > 0 && logfields->disp_prog)
576  			b_left = display_printf(&dspbuf, ": %s", program_name);
577  	
578  		if (b_left > 0 && logfields->disp_prog
579  		    && logfields->disp_pid)
580  			b_left = display_cat(&dspbuf, "-");
581  	
582  		if (b_left > 0 && logfields->disp_pid)
583  			b_left = display_printf(&dspbuf, "%d", getpid());
584  	
585  		if (b_left > 0
586  		    && (logfields->disp_prog || logfields->disp_pid)
587  		    && !logfields->disp_threadname)
588  			(void) display_cat(&dspbuf, " ");
589  	
590  		b_left = display_start(&tdfbuf);
591  	
592  		if (b_left <= 0)
593  			return;
594  	
595  		if (logfields->datefmt == TD_LOCAL
596  		    && logfields->timefmt == TD_LOCAL) {
597  			b_left = display_cat(&tdfbuf, "%c ");
598  		} else {
599  			switch (logfields->datefmt) {
600  			case TD_GANESHA:
601  				b_left = display_cat(&tdfbuf, "%d/%m/%Y ");
602  				break;
603  			case TD_8601:
604  				b_left = display_cat(&tdfbuf, "%F ");
605  				break;
606  			case TD_LOCAL:
607  				b_left = display_cat(&tdfbuf, "%x ");
608  				break;
609  			case TD_SYSLOG:
610  				b_left = display_cat(&tdfbuf, "%b %e ");
611  				break;
612  			case TD_SYSLOG_USEC:
613  				if (logfields->timefmt == TD_SYSLOG_USEC)
614  					b_left = display_cat(&tdfbuf, "%F");
615  				else
616  					b_left = display_cat(&tdfbuf, "%F ");
617  				break;
618  			case TD_USER:
619  				b_left = display_printf(&tdfbuf, "%s ",
620  					logfields->user_date_fmt);
621  				break;
622  			case TD_NONE:
623  			default:
624  				break;
625  			}
626  	
627  			if (b_left <= 0)
628  				return;
629  	
630  			switch (logfields->timefmt) {
631  			case TD_GANESHA:
632  				b_left = display_cat(&tdfbuf, "%H:%M:%S ");
633  				break;
634  			case TD_SYSLOG:
635  			case TD_8601:
636  			case TD_LOCAL:
637  				b_left = display_cat(&tdfbuf, "%X ");
638  				break;
639  			case TD_SYSLOG_USEC:
640  				b_left = display_cat(&tdfbuf, "T%H:%M:%S.%%06u%z ");
641  				break;
642  			case TD_USER:
643  				b_left = display_printf(&tdfbuf, "%s ",
644  					logfields->user_time_fmt);
645  				break;
646  			case TD_NONE:
647  			default:
648  				break;
649  			}
650  	
651  		}
652  	
653  		/* Trim trailing blank from date time format. */
654  		if (date_time_fmt[0] != '\0' &&
655  		    date_time_fmt[strlen(date_time_fmt) - 1] == ' ')
656  			date_time_fmt[strlen(date_time_fmt) - 1] = '\0';
657  	}
658  	
659  	static void set_logging_from_env(void)
660  	{
661  		char *env_value;
662  		int newlevel, component, oldlevel;
663  	
664  		for (component = COMPONENT_ALL; component < COMPONENT_COUNT;
665  		     component++) {
666  			env_value = getenv(LogComponents[component].comp_name);
667  			if (env_value == NULL)
668  				continue;
669  			newlevel = ReturnLevelAscii(env_value);
670  			if (newlevel == -1) {
671  				LogCrit(COMPONENT_LOG,
672  					"Environment variable %s exists, but the value %s is not a valid log level.",
673  					LogComponents[component].comp_name,
674  					env_value);
675  				continue;
676  			}
677  			oldlevel = component_log_level[component];
678  			if (component == COMPONENT_ALL)
679  				_SetLevelDebug(newlevel);
680  			else
681  				SetComponentLogLevel(component, newlevel);
682  			LogComponents[component].comp_env_set = true;
683  			LogChanges(
684  			     "Using environment variable to switch log level for %s from %s to %s",
685  			     LogComponents[component].comp_name,
686  			     ReturnLevelInt(oldlevel),
687  			     ReturnLevelInt(newlevel));
688  		}
689  	
690  	}				/* InitLogging */
691  	
692  	/**
693  	 *
694  	 * @brief Finds a log facility by name
695  	 *
696  	 * Must be called under the rwlock
697  	 *
698  	 * @param[in]  name The name of the facility to be found
699  	 *
700  	 * @retval NULL No facility by that name
701  	 * @retval non-NULL Pointer to the facility structure
702  	 *
703  	 */
704  	static struct log_facility *find_log_facility(const char *name)
705  	{
706  		struct glist_head *glist;
707  		struct log_facility *facility;
708  	
709  		glist_for_each(glist, &facility_list) {
710  			facility = glist_entry(glist, struct log_facility, lf_list);
711  			if (!strcasecmp(name, facility->lf_name))
712  				return facility;
713  		}
714  	
715  		return NULL;
716  	}
717  	
718  	/**
719  	 * @brief Create a logging facility
720  	 *
721  	 * A logging facility outputs log messages using the helper function
722  	 * log_func.  See below for enabling/disabling.
723  	 *
724  	 * @param name       [IN] the name of the new logger
725  	 * @param log_func   [IN] function pointer to the helper
726  	 * @param max_level  [IN] maximum message level this logger will handle.
727  	 * @param header     [IN] detail level for header part of messages
728  	 * @param private    [IN] logger specific argument.
729  	 *
730  	 * @return 0 on success, -errno for failure
731  	 */
732  	
733  	int create_log_facility(const char *name, lf_function_t *log_func,
734  				log_levels_t max_level, log_header_t header,
735  				void *private)
736  	{
737  		struct log_facility *facility;
738  	
739  		if (name == NULL || *name == '\0')
740  			return -EINVAL;
741  		if (max_level < NIV_NULL || max_level >= NB_LOG_LEVEL)
742  			return -EINVAL;
743  		if (log_func == log_to_file && private != NULL) {
744  			char *dir;
745  			int rc;
746  	
747  			if (*(char *)private == '\0' ||
748  			    strlen(private) >= MAXPATHLEN) {
749  				LogCrit(COMPONENT_LOG,
750  					 "New log file path empty or too long");
751  				return -EINVAL;
752  			}
753  			dir = alloca(strlen(private) + 1);
754  			strcpy(dir, private);
755  			dir = dirname(dir);
756  			rc = access(dir, W_OK);
757  			if (rc != 0) {
758  				rc = errno;
759  				LogCrit(COMPONENT_LOG,
760  					 "Cannot create new log file (%s), because: %s",
761  					 (char *)private, strerror(rc));
762  				return -rc;
763  			}
764  		}
765  		PTHREAD_RWLOCK_wrlock(&log_rwlock);
766  	
767  		facility = find_log_facility(name);
768  	
769  		if (facility != NULL) {
770  			PTHREAD_RWLOCK_unlock(&log_rwlock);
771  	
772  			LogInfo(COMPONENT_LOG, "Facility %s already exists", name);
773  	
774  			return -EEXIST;
775  		}
776  	
777  		facility = gsh_calloc(1, sizeof(*facility));
778  	
779  		facility->lf_name = gsh_strdup(name);
780  		facility->lf_func = log_func;
781  		facility->lf_max_level = max_level;
782  		facility->lf_headers = header;
783  	
784  		if (log_func == log_to_file && private != NULL)
785  			facility->lf_private = gsh_strdup(private);
786  		else
787  			facility->lf_private = private;
788  	
789  		glist_add_tail(&facility_list, &facility->lf_list);
790  	
791  		PTHREAD_RWLOCK_unlock(&log_rwlock);
792  	
793  		LogInfo(COMPONENT_LOG, "Created log facility %s",
794  			facility->lf_name);
795  	
796  		return 0;
797  	}
798  	
799  	/**
800  	 * @brief Release a logger facility
801  	 *
802  	 * Release the named facility and all its resources.
803  	 * disable it first if it is active.  It will refuse to
804  	 * release the default logger because that could leave the server
805  	 * with no place to send messages.
806  	 *
807  	 * @param name [IN] name of soon to be deceased logger
808  	 *
809  	 * @returns always.  The logger is not disabled or released on errors
810  	 */
811  	
812  	void release_log_facility(const char *name)
813  	{
814  		struct log_facility *facility;
815  	
816  		PTHREAD_RWLOCK_wrlock(&log_rwlock);
817  		facility = find_log_facility(name);
818  		if (facility == NULL) {
819  			PTHREAD_RWLOCK_unlock(&log_rwlock);
820  			LogCrit(COMPONENT_LOG,
821  				 "Attempting release of non-existant log facility (%s)",
822  				 name);
823  			return;
824  		}
825  		if (facility == default_facility) {
826  			PTHREAD_RWLOCK_unlock(&log_rwlock);
827  			LogCrit(COMPONENT_LOG,
828  				 "Attempting to release default log facility (%s)",
829  				 name);
830  			return;
831  		}
832  		if (!glist_null(&facility->lf_active))
833  			glist_del(&facility->lf_active);
834  		glist_del(&facility->lf_list);
835  		PTHREAD_RWLOCK_unlock(&log_rwlock);
836  		if (facility->lf_func == log_to_file &&
837  		    facility->lf_private != NULL)
838  			gsh_free(facility->lf_private);
839  		gsh_free(facility->lf_name);
840  		gsh_free(facility);
841  	}
842  	
843  	/**
844  	 * @brief Enable the named logger
845  	 *
846  	 * Enabling a logger adds it to the list of facilites that will be
847  	 * used to report messages.
848  	 *
849  	 * @param name [IN] the name of the logger to enable
850  	 *
851  	 * @return 0 on success, -errno on errors.
852  	 */
853  	
854  	int enable_log_facility(const char *name)
855  	{
856  		struct log_facility *facility;
857  	
858  		if (name == NULL || *name == '\0')
859  			return -EINVAL;
860  		PTHREAD_RWLOCK_wrlock(&log_rwlock);
861  		facility = find_log_facility(name);
862  		if (facility == NULL) {
863  			PTHREAD_RWLOCK_unlock(&log_rwlock);
864  			LogInfo(COMPONENT_LOG, "Facility %s does not exist", name);
865  			return -ENOENT;
866  		}
867  	
868  		if (glist_null(&facility->lf_active))
869  			glist_add_tail(&active_facility_list, &facility->lf_active);
870  	
871  		if (facility->lf_headers > max_headers)
872  			max_headers = facility->lf_headers;
873  		PTHREAD_RWLOCK_unlock(&log_rwlock);
874  		return 0;
875  	}
876  	
877  	/**
878  	 * @brief Disable the named logger
879  	 *
880  	 * Disabling a logger ends logging output to that facility.
881  	 * Disabling the default logger is not allowed.  Another facility
882  	 * must be set instead.  Loggers can be re-enabled at any time.
883  	 *
884  	 * @param name [IN] the name of the logger to enable
885  	 *
886  	 * @return 0 on success, -errno on errors.
887  	 */
888  	
889  	int disable_log_facility(const char *name)
890  	{
891  		struct log_facility *facility;
892  	
893  		if (name == NULL || *name == '\0')
894  			return -EINVAL;
895  		PTHREAD_RWLOCK_wrlock(&log_rwlock);
896  		facility = find_log_facility(name);
897  		if (facility == NULL) {
898  			PTHREAD_RWLOCK_unlock(&log_rwlock);
899  			LogInfo(COMPONENT_LOG, "Facility %s does not exist", name);
900  			return -ENOENT;
901  		}
902  		if (glist_null(&facility->lf_active)) {
903  			PTHREAD_RWLOCK_unlock(&log_rwlock);
904  			LogDebug(COMPONENT_LOG,
905  				 "Log facility (%s) is already disabled",
906  				 name);
907  			return 0;
908  		}
909  		if (facility == default_facility) {
910  			PTHREAD_RWLOCK_unlock(&log_rwlock);
911  			LogCrit(COMPONENT_LOG,
912  				 "Cannot disable the default logger (%s)",
913  				 default_facility->lf_name);
914  			return -EPERM;
915  		}
916  		glist_del(&facility->lf_active);
917  		if (facility->lf_headers == max_headers) {
918  			struct glist_head *glist;
919  			struct log_facility *found;
920  	
921  			max_headers = LH_NONE;
922  			glist_for_each(glist, &active_facility_list) {
923  				found = glist_entry(glist,
924  						    struct log_facility, lf_active);
925  				if (found->lf_headers > max_headers)
926  					max_headers = found->lf_headers;
927  			}
928  		}
929  		PTHREAD_RWLOCK_unlock(&log_rwlock);
930  		return 0;
931  	}
932  	
933  	/**
934  	 * @brief Set the named logger as the default logger
935  	 *
936  	 * The default logger can not be released sp we set another one as
937  	 * the default instead.  The previous default logger is disabled.
938  	 *
939  	 * @param name [IN] the name of the logger to enable
940  	 *
941  	 * @return 0 on success, -errno on errors.
942  	 */
943  	
944  	static int set_default_log_facility(const char *name)
945  	{
946  		struct log_facility *facility;
947  	
948  		if (name == NULL || *name == '\0')
949  			return -EINVAL;
950  	
951  		PTHREAD_RWLOCK_wrlock(&log_rwlock);
952  		facility = find_log_facility(name);
953  		if (facility == NULL) {
954  			PTHREAD_RWLOCK_unlock(&log_rwlock);
955  			LogCrit(COMPONENT_LOG, "Facility %s does not exist", name);
956  			return -ENOENT;
957  		}
958  		if (facility == default_facility)
959  			goto out;
960  		if (glist_null(&facility->lf_active))
961  			glist_add_tail(&active_facility_list, &facility->lf_active);
962  		if (default_facility != NULL) {
963  			assert(!glist_null(&default_facility->lf_active));
964  			glist_del(&default_facility->lf_active);
965  			if (facility->lf_headers != max_headers) {
966  				struct glist_head *glist;
967  				struct log_facility *found;
968  	
969  				max_headers = LH_NONE;
970  				glist_for_each(glist, &active_facility_list) {
971  					found = glist_entry(glist,
972  							    struct log_facility,
973  							    lf_active);
974  					if (found->lf_headers > max_headers)
975  						max_headers = found->lf_headers;
976  				}
977  			}
978  		} else if (facility->lf_headers > max_headers)
979  			max_headers = facility->lf_headers;
980  		default_facility = facility;
981  	out:
982  		PTHREAD_RWLOCK_unlock(&log_rwlock);
983  		return 0;
984  	}
985  	
986  	/**
987  	 * @brief Set the destination for logger
988  	 *
989  	 * This function only works if the facility outputs to files.
990  	 *
991  	 * @param name [IN] the name of the facility
992  	 * @param dest [IN] "stdout", "stderr", "syslog", or a file path
993  	 *
994  	 * @return 0 on success, -errno on errors
995  	 */
996  	
997  	int set_log_destination(const char *name, char *dest)
998  	{
999  		struct log_facility *facility;
1000 		int rc;
1001 	
1002 		if (name == NULL || *name == '\0')
1003 			return -EINVAL;
1004 		if (dest == NULL ||
1005 		    *dest == '\0' ||
1006 		    strlen(dest) >= MAXPATHLEN) {
1007 			LogCrit(COMPONENT_LOG,
1008 				 "New log file path empty or too long");
1009 			return -EINVAL;
1010 		}
1011 		PTHREAD_RWLOCK_wrlock(&log_rwlock);
1012 		facility = find_log_facility(name);
1013 		if (facility == NULL) {
1014 			PTHREAD_RWLOCK_unlock(&log_rwlock);
1015 			LogCrit(COMPONENT_LOG,
1016 				 "No such log facility (%s)",
1017 				 name);
1018 			return -ENOENT;
1019 		}
1020 		if (facility->lf_func == log_to_file) {
1021 			char *logfile, *dir;
1022 	
1023 			dir = alloca(strlen(dest) + 1);
1024 			strcpy(dir, dest);
1025 			dir = dirname(dir);
1026 			rc = access(dir, W_OK);
1027 			if (rc != 0) {
1028 				PTHREAD_RWLOCK_unlock(&log_rwlock);
1029 				LogCrit(COMPONENT_LOG,
1030 					"Cannot create new log file (%s), because: %s",
1031 					dest, strerror(errno));
1032 				return -errno;
1033 			}
1034 			logfile = gsh_strdup(dest);
1035 			gsh_free(facility->lf_private);
1036 			facility->lf_private = logfile;
1037 		} else if (facility->lf_func == log_to_stream) {
1038 			FILE *out;
1039 	
1040 			if (strcasecmp(dest, "stdout") == 0) {
1041 				out = stdout;
1042 			} else if (strcasecmp(dest, "stderr") == 0) {
1043 				out = stderr;
1044 			} else {
1045 				PTHREAD_RWLOCK_unlock(&log_rwlock);
1046 				LogCrit(COMPONENT_LOG,
1047 					"Expected STDERR or STDOUT, not (%s)",
1048 					dest);
1049 				return -EINVAL;
1050 			}
1051 			facility->lf_private = out;
1052 		} else {
1053 			PTHREAD_RWLOCK_unlock(&log_rwlock);
1054 			LogCrit(COMPONENT_LOG,
1055 				 "Log facility %s destination is not changeable",
1056 				facility->lf_name);
1057 			return -EINVAL;
1058 		}
1059 		PTHREAD_RWLOCK_unlock(&log_rwlock);
1060 		return 0;
1061 	}
1062 	
1063 	/**
1064 	 * @brief Set maximum logging level for a facilty
1065 	 *
1066 	 * @param name [IN] the name of the facility
1067 	 * @param max_level [IN] Maximum level
1068 	 *
1069 	 *
1070 	 * @return 0 on success, -errno on errors
1071 	 */
1072 	
1073 	int set_log_level(const char *name, log_levels_t max_level)
1074 	{
1075 		struct log_facility *facility;
1076 	
1077 		if (name == NULL || *name == '\0')
1078 			return -EINVAL;
1079 		if (max_level < NIV_NULL || max_level >= NB_LOG_LEVEL)
1080 			return -EINVAL;
1081 		PTHREAD_RWLOCK_wrlock(&log_rwlock);
1082 		facility = find_log_facility(name);
1083 		if (facility == NULL) {
1084 			PTHREAD_RWLOCK_unlock(&log_rwlock);
1085 			LogCrit(COMPONENT_LOG,
1086 				 "No such log facility (%s)",
1087 				 name);
1088 			return -ENOENT;
1089 		}
1090 		facility->lf_max_level = max_level;
1091 		PTHREAD_RWLOCK_unlock(&log_rwlock);
1092 		return 0;
1093 	}
1094 	
1095 	/**
1096 	 * @brief Initialize Logging
1097 	 *
1098 	 * Called very early in server init to make logging available as
1099 	 * soon as possible. Create a logger to stderr first and make it
1100 	 * the default.  We are forced to fprintf to stderr by hand until
1101 	 * this happens.  Once this is up, the logger is working.
1102 	 * We then get stdout and syslog loggers init'd.
1103 	 * If log_path (passed in via -L on the command line), we get a
1104 	 * FILE logger going and make it our default logger.  Otherwise,
1105 	 * we use syslog as the default.
1106 	 *
1107 	 * @param log_path    [IN] optarg from -L, otherwise NULL
1108 	 * @param debug_level [IN] global debug level from -N optarg
1109 	 */
1110 	
1111 	void init_logging(const char *log_path, const int debug_level)
1112 	{
1113 		int rc;
1114 	
1115 		/* Finish initialization of and register log facilities. */
1116 		glist_init(&facility_list);
1117 		glist_init(&active_facility_list);
1118 	
1119 		/* Initialize const_log_str to defaults. Ganesha can start logging
1120 		 * before the LOG config is processed (in fact, LOG config can itself
1121 		 * issue log messages to indicate errors.
1122 		 */
1123 		set_const_log_str();
1124 	
1125 		rc = create_log_facility("STDERR", log_to_stream,
1126 					 NIV_FULL_DEBUG, LH_ALL, stderr);
1127 		if (rc != 0) {
1128 			fprintf(stderr, "Create error (%s) for STDERR log facility!",
1129 				strerror(-rc));
1130 			Fatal();
1131 		}
1132 		rc = set_default_log_facility("STDERR");
1133 		if (rc != 0) {
1134 			fprintf(stderr, "Enable error (%s) for STDERR log facility!",
1135 				strerror(-rc));
1136 			Fatal();
1137 		}
1138 		rc = create_log_facility("STDOUT", log_to_stream,
1139 					 NIV_FULL_DEBUG, LH_ALL, stdout);
1140 		if (rc != 0)
1141 			LogFatal(COMPONENT_LOG,
1142 				 "Create error (%s) for STDOUT log facility!",
1143 				strerror(-rc));
1144 		rc = create_log_facility("SYSLOG", log_to_syslog,
1145 					 NIV_FULL_DEBUG, LH_COMPONENT, NULL);
1146 		if (rc != 0)
1147 			LogFatal(COMPONENT_LOG,
1148 				 "Create error (%s) for SYSLOG log facility!",
1149 				 strerror(-rc));
1150 	
1151 		if (log_path) {
1152 			if ((strcmp(log_path, "STDERR") == 0) ||
1153 			    (strcmp(log_path, "SYSLOG") == 0) ||
1154 			    (strcmp(log_path, "STDOUT") == 0)) {
1155 				rc = set_default_log_facility(log_path);
1156 				if (rc != 0)
1157 					LogFatal(COMPONENT_LOG,
1158 						 "Enable error (%s) for %s logging!",
1159 						 strerror(-rc), log_path);
1160 			} else {
1161 				rc = create_log_facility("FILE", log_to_file,
1162 							 NIV_FULL_DEBUG, LH_ALL,
1163 							 (void *)log_path);
1164 				if (rc != 0)
1165 					LogFatal(COMPONENT_LOG,
1166 						 "Create error (%s) for FILE (%s) logging!",
1167 						 strerror(-rc), log_path);
1168 				rc = set_default_log_facility("FILE");
1169 				if (rc != 0)
1170 					LogFatal(COMPONENT_LOG,
1171 						 "Enable error (%s) for FILE (%s) logging!",
1172 						 strerror(-rc), log_path);
1173 			}
1174 		} else {
1175 			/* Fall back to SYSLOG as the first default facility */
1176 			rc = set_default_log_facility("SYSLOG");
1177 			if (rc != 0)
1178 				LogFatal(COMPONENT_LOG,
1179 					 "Enable error (%s) for SYSLOG logging!",
1180 					 strerror(-rc));
1181 		}
1182 		if (debug_level >= 0)
1183 			SetLevelDebug(debug_level);
1184 	
1185 		set_logging_from_env();
1186 	
1187 		ArmSignal(SIGUSR1, IncrementLevelDebug);
1188 		ArmSignal(SIGUSR2, DecrementLevelDebug);
1189 	}
1190 	
1191 	/*
1192 	 * Routines for managing error messages
1193 	 */
1194 	static int log_to_syslog(log_header_t headers, void *private,
1195 				 log_levels_t level,
1196 				 struct display_buffer *buffer, char *compstr,
1197 				 char *message)
1198 	{
1199 		if (!syslog_opened) {
1200 			openlog("nfs-ganesha", LOG_PID, LOG_USER);
1201 			syslog_opened = 1;
1202 		}
1203 	
1204 		/* Writing to syslog. */
1205 		syslog(tabLogLevel[level].syslog_level, "%s", compstr);
1206 	
1207 		return 0;
1208 	}
1209 	
1210 	static int log_to_file(log_header_t headers, void *private,
1211 			       log_levels_t level,
1212 			       struct display_buffer *buffer, char *compstr,
1213 			       char *message)
1214 	{
1215 		int fd, my_status, len, rc = 0;
1216 		char *path = private;
1217 	
1218 		len = display_buffer_len(buffer);
1219 	
1220 		/* Add newline to end of buffer */
1221 		buffer->b_start[len] = '\n';
1222 		buffer->b_start[len + 1] = '\0';
1223 	
1224 		fd = open(path, O_WRONLY | O_APPEND | O_CREAT, log_mask);
1225 	
1226 		if (fd != -1) {
1227 			rc = write(fd, buffer->b_start, len + 1);
1228 	
1229 			if (rc < (len + 1)) {
1230 				if (rc >= 0)
1231 					my_status = ENOSPC;
1232 				else
1233 					my_status = errno;
1234 	
1235 				(void)close(fd);
1236 	
1237 				goto error;
1238 			}
1239 	
1240 			rc = close(fd);
1241 	
1242 			if (rc == 0)
1243 				goto out;
1244 		}
1245 	
1246 		my_status = errno;
1247 	
1248 	 error:
1249 	
1250 		fprintf(stderr,
1251 			"Error: couldn't complete write to the log file %s status=%d (%s) message was:\n%s",
1252 			path, my_status, strerror(my_status), buffer->b_start);
1253 	
1254 	 out:
1255 	
1256 		/* Remove newline from buffer */
1257 		buffer->b_start[len] = '\0';
1258 	
1259 		return rc;
1260 	}
1261 	
1262 	static int log_to_stream(log_header_t headers, void *private,
1263 				 log_levels_t level,
1264 				 struct display_buffer *buffer, char *compstr,
1265 				 char *message)
1266 	{
1267 		FILE *stream = private;
1268 		int rc;
1269 		char *msg = buffer->b_start;
1270 		int len;
1271 	
1272 		len = display_buffer_len(buffer);
1273 	
1274 		/* Add newline to end of buffer */
1275 		buffer->b_start[len] = '\n';
1276 		buffer->b_start[len + 1] = '\0';
1277 	
1278 		switch (headers) {
1279 		case LH_NONE:
1280 			msg = message;
1281 			break;
1282 		case LH_COMPONENT:
1283 			msg = compstr;
1284 			break;
1285 		case LH_ALL:
1286 			msg = buffer->b_start;
1287 			break;
1288 		default:
1289 			msg = "Somehow header level got messed up!!";
1290 		}
1291 	
1292 		rc = fputs(msg, stream);
1293 	
1294 		if (rc != EOF)
1295 			rc = fflush(stream);
1296 	
1297 		/* Remove newline from buffer */
1298 		buffer->b_start[len] = '\0';
1299 	
1300 		if (rc == EOF)
1301 			return -1;
1302 		else
1303 			return 0;
1304 	}
1305 	
1306 	int display_timeval(struct display_buffer *dspbuf, struct timeval *tv)
1307 	{
1308 		char *fmt = date_time_fmt;
1309 		int b_left = display_start(dspbuf);
1310 		struct tm the_date;
1311 		char tbuf[MAX_TD_FMT_LEN];
1312 		time_t tm = tv->tv_sec;
1313 	
1314 		if (b_left <= 0)
1315 			return b_left;
1316 	
1317 		if (logfields->datefmt == TD_NONE && logfields->timefmt == TD_NONE)
1318 			fmt = "%c ";
1319 	
1320 		Localtime_r(&tm, &the_date);
1321 	
1322 		/* Earlier we build the date/time format string in
1323 		 * date_time_fmt, now use that to format the time and/or date.
1324 		 * If time format is TD_SYSLOG_USEC, then we need an additional
1325 		 * step to add the microseconds (since strftime just takes a
1326 		 * struct tm which was filled in from a time_t and thus does not
1327 		 * have microseconds.
1328 		 */
1329 		if (strftime(tbuf, sizeof(tbuf), fmt, &the_date) != 0) {
1330 			if (logfields->timefmt == TD_SYSLOG_USEC)
1331 				b_left = display_printf(dspbuf, tbuf, tv->tv_usec);
1332 			else
1333 				b_left = display_cat(dspbuf, tbuf);
1334 		}
1335 	
1336 		return b_left;
1337 	}
1338 	
1339 	int display_timespec(struct display_buffer *dspbuf, struct timespec *ts)
1340 	{
1341 		char *fmt = date_time_fmt;
1342 		int b_left = display_start(dspbuf);
1343 		struct tm the_date;
1344 		char tbuf[MAX_TD_FMT_LEN];
1345 		time_t tm = ts->tv_sec;
1346 	
1347 		if (b_left <= 0)
1348 			return b_left;
1349 	
1350 		if (logfields->datefmt == TD_NONE && logfields->timefmt == TD_NONE)
1351 			fmt = "%c ";
1352 	
1353 		Localtime_r(&tm, &the_date);
1354 	
1355 		/* Earlier we build the date/time format string in
1356 		 * date_time_fmt, now use that to format the time and/or date.
1357 		 * If time format is TD_SYSLOG_USEC, then we need an additional
1358 		 * step to add the microseconds (since strftime just takes a
1359 		 * struct tm which was filled in from a time_t and thus does not
1360 		 * have microseconds.
1361 		 */
1362 		if (strftime(tbuf, sizeof(tbuf), fmt, &the_date) != 0) {
1363 			if (logfields->timefmt == TD_SYSLOG_USEC)
1364 				b_left = display_printf(dspbuf, tbuf, ts->tv_nsec);
1365 			else
1366 				b_left = display_cat(dspbuf, tbuf);
1367 		}
1368 	
1369 		return b_left;
1370 	}
1371 	
1372 	static int display_log_header(struct display_buffer *dsp_log)
1373 	{
1374 		int b_left = display_start(dsp_log);
1375 	
1376 		if (b_left <= 0 || max_headers < LH_ALL)
1377 			return b_left;
1378 	
1379 		/* Print date and/or time if either flag is enabled. */
1380 		if (b_left > 0
1381 		    && (logfields->datefmt != TD_NONE
1382 			|| logfields->timefmt != TD_NONE)) {
1383 			struct timeval tv;
1384 	
1385 			if (logfields->timefmt == TD_SYSLOG_USEC) {
1386 				gettimeofday(&tv, NULL);
1387 			} else {
1388 				tv.tv_sec = time(NULL);
1389 				tv.tv_usec = 0;
1390 			}
1391 	
1392 			b_left = display_timeval(dsp_log, &tv);
1393 	
1394 			if (b_left > 0)
1395 				b_left = display_cat(dsp_log, " ");
1396 		}
1397 	
1398 		if (b_left > 0 && const_log_str[0] != '\0')
1399 			b_left = display_cat(dsp_log, const_log_str);
1400 	
1401 		/* If thread name will not follow, need a : separator */
1402 		if (b_left > 0 && !logfields->disp_threadname)
1403 			b_left = display_cat(dsp_log, ": ");
1404 	
1405 		/* If we overflowed the buffer with the header, just skip it. */
1406 		if (b_left == 0) {
1407 			display_reset_buffer(dsp_log);
1408 			b_left = display_start(dsp_log);
1409 		}
1410 	
1411 		/* The message will now start at dsp_log.b_current */
1412 		return b_left;
1413 	}
1414 	
1415 	static int display_log_component(struct display_buffer *dsp_log,
1416 					 log_components_t component, const char *file,
1417 					 int line, const char *function, int level)
1418 	{
1419 		int b_left = display_start(dsp_log);
1420 	
1421 		if (b_left <= 0 || max_headers < LH_COMPONENT)
1422 			return b_left;
1423 	
1424 		if (b_left > 0 && logfields->disp_clientip) {
1425 			if (clientip)
1426 				b_left = display_printf(dsp_log, "[%s] ",
1427 							clientip);
1428 			else
1429 				b_left = display_printf(dsp_log, "[none] ");
1430 		}
1431 	
1432 		if (b_left > 0 && logfields->disp_threadname) {
1433 			if (thread_name[0] != '\0')
1434 				b_left = display_printf(dsp_log, "[%s] ",
1435 							thread_name);
1436 			else
1437 				b_left = display_printf(dsp_log, "[%p] ",
1438 							thread_name);
1439 		}
1440 	
1441 		if (b_left > 0 && logfields->disp_filename) {
1442 			if (logfields->disp_linenum)
1443 				b_left = display_printf(dsp_log, "%s:", file);
1444 			else
1445 				b_left = display_printf(dsp_log, "%s :", file);
1446 		}
1447 	
1448 		if (b_left > 0 && logfields->disp_linenum)
1449 			b_left = display_printf(dsp_log, "%d :", line);
1450 	
1451 		if (b_left > 0 && logfields->disp_funct)
1452 			b_left = display_printf(dsp_log, "%s :", function);
1453 	
1454 		if (b_left > 0 && logfields->disp_comp)
1455 			b_left =
1456 			    display_printf(dsp_log, "%s :",
1457 					   LogComponents[component].comp_str);
1458 	
1459 		if (b_left > 0 && logfields->disp_level)
1460 			b_left =
1461 			    display_printf(dsp_log, "%s :",
1462 					   tabLogLevel[level].short_str);
1463 	
1464 		/* If we overflowed the buffer with the header, just skip it. */
1465 		if (b_left == 0) {
1466 			display_reset_buffer(dsp_log);
1467 			b_left = display_start(dsp_log);
1468 		}
1469 	
1470 		return b_left;
1471 	}
1472 	
1473 	void display_log_component_level(log_components_t component, const char *file,
1474 					int line, const char *function,
1475 					log_levels_t level, const char *format,
1476 					va_list arguments)
1477 	{
1478 		char *compstr;
1479 		char *message;
1480 		int b_left;
1481 		struct glist_head *glist;
1482 		struct log_facility *facility;
1483 		struct display_buffer dsp_log = {sizeof(log_buffer),
1484 						 log_buffer, log_buffer};
1485 	
1486 		/* Build up the messsage and capture the various positions in it. */
1487 		b_left = display_log_header(&dsp_log);
1488 	
1489 		if (b_left > 0)
1490 			compstr = dsp_log.b_current;
1491 		else
1492 			compstr = dsp_log.b_start;
1493 	
1494 		if (b_left > 0)
1495 			b_left =
1496 			    display_log_component(&dsp_log, component, file, line,
1497 						  function, level);
1498 	
1499 		if (b_left > 0)
1500 			message = dsp_log.b_current;
1501 		else
1502 			message = dsp_log.b_start;
1503 	
1504 		if (b_left > 0)
1505 			b_left = display_vprintf(&dsp_log, format, arguments);
1506 	
1507 	#ifdef USE_LTTNG
1508 		tracepoint(ganesha_logger, log,
1509 			   component, level, file, line, function, message);
1510 	#endif
1511 	
1512 		PTHREAD_RWLOCK_rdlock(&log_rwlock);
1513 	
1514 		glist_for_each(glist, &active_facility_list) {
1515 			facility = glist_entry(glist, struct log_facility, lf_active);
1516 	
1517 			if (level <= facility->lf_max_level
1518 			    && facility->lf_func != NULL)
1519 				facility->lf_func(facility->lf_headers,
1520 						  facility->lf_private,
1521 						  level, &dsp_log,
1522 						  compstr, message);
1523 		}
1524 	
1525 		PTHREAD_RWLOCK_unlock(&log_rwlock);
1526 	
1527 		if (level == NIV_FATAL)
1528 			Fatal();
1529 	}
1530 	
1531 	/**
1532 	 * @brief Default logging levels
1533 	 *
1534 	 * These are for early initialization and whenever we
1535 	 * have to fall back to something that will at least work...
1536 	 */
1537 	
1538 	static log_levels_t default_log_levels[] = {
1539 		[COMPONENT_ALL] = NIV_NULL,
1540 		[COMPONENT_LOG] = NIV_EVENT,
1541 		[COMPONENT_MEM_ALLOC] = NIV_EVENT,
1542 		[COMPONENT_MEMLEAKS] = NIV_EVENT,
1543 		[COMPONENT_FSAL] = NIV_EVENT,
1544 		[COMPONENT_NFSPROTO] = NIV_EVENT,
1545 		[COMPONENT_NFS_V4] = NIV_EVENT,
1546 		[COMPONENT_EXPORT] = NIV_EVENT,
1547 		[COMPONENT_FILEHANDLE] = NIV_EVENT,
1548 		[COMPONENT_DISPATCH] = NIV_EVENT,
1549 		[COMPONENT_CACHE_INODE] = NIV_EVENT,
1550 		[COMPONENT_CACHE_INODE_LRU] = NIV_EVENT,
1551 		[COMPONENT_HASHTABLE] = NIV_EVENT,
1552 		[COMPONENT_HASHTABLE_CACHE] = NIV_EVENT,
1553 		[COMPONENT_DUPREQ] = NIV_EVENT,
1554 		[COMPONENT_INIT] = NIV_EVENT,
1555 		[COMPONENT_MAIN] = NIV_EVENT,
1556 		[COMPONENT_IDMAPPER] = NIV_EVENT,
1557 		[COMPONENT_NFS_READDIR] = NIV_EVENT,
1558 		[COMPONENT_NFS_V4_LOCK] = NIV_EVENT,
1559 		[COMPONENT_CONFIG] = NIV_EVENT,
1560 		[COMPONENT_CLIENTID] = NIV_EVENT,
1561 		[COMPONENT_SESSIONS] = NIV_EVENT,
1562 		[COMPONENT_PNFS] = NIV_EVENT,
1563 		[COMPONENT_RW_LOCK] = NIV_EVENT,
1564 		[COMPONENT_NLM] = NIV_EVENT,
1565 		[COMPONENT_RPC] = NIV_EVENT,
1566 		[COMPONENT_TIRPC] = NIV_EVENT,
1567 		[COMPONENT_NFS_CB] = NIV_EVENT,
1568 		[COMPONENT_THREAD] = NIV_EVENT,
1569 		[COMPONENT_NFS_V4_ACL] = NIV_EVENT,
1570 		[COMPONENT_STATE] = NIV_EVENT,
1571 		[COMPONENT_9P] = NIV_EVENT,
1572 		[COMPONENT_9P_DISPATCH] = NIV_EVENT,
1573 		[COMPONENT_FSAL_UP] = NIV_EVENT,
1574 		[COMPONENT_DBUS] = NIV_EVENT,
1575 		[COMPONENT_NFS_MSK] = NIV_EVENT
1576 	};
1577 	
1578 	log_levels_t *component_log_level = default_log_levels;
1579 	
1580 	struct log_component_info LogComponents[COMPONENT_COUNT] = {
1581 		[COMPONENT_ALL] = {
1582 			.comp_name = "COMPONENT_ALL",
1583 			.comp_str = "",},
1584 		[COMPONENT_LOG] = {
1585 			.comp_name = "COMPONENT_LOG",
1586 			.comp_str = "LOG",},
1587 		[COMPONENT_MEM_ALLOC] = {
1588 			.comp_name = "COMPONENT_MEM_ALLOC",
1589 			.comp_str = "MEM ALLOC",},
1590 		[COMPONENT_MEMLEAKS] = {
1591 			.comp_name = "COMPONENT_MEMLEAKS",
1592 			.comp_str = "LEAKS",},
1593 		[COMPONENT_FSAL] = {
1594 			.comp_name = "COMPONENT_FSAL",
1595 			.comp_str = "FSAL",},
1596 		[COMPONENT_NFSPROTO] = {
1597 			.comp_name = "COMPONENT_NFSPROTO",
1598 			.comp_str = "NFS3",},
1599 		[COMPONENT_NFS_V4] = {
1600 			.comp_name = "COMPONENT_NFS_V4",
1601 			.comp_str = "NFS4",},
1602 		[COMPONENT_EXPORT] = {
1603 			.comp_name = "COMPONENT_EXPORT",
1604 			.comp_str = "EXPORT",},
1605 		[COMPONENT_FILEHANDLE] = {
1606 			.comp_name = "COMPONENT_FILEHANDLE",
1607 			.comp_str = "FH",},
1608 		[COMPONENT_DISPATCH] = {
1609 			.comp_name = "COMPONENT_DISPATCH",
1610 			.comp_str = "DISP",},
1611 		[COMPONENT_CACHE_INODE] = {
1612 			.comp_name = "COMPONENT_CACHE_INODE",
1613 			.comp_str = "INODE",},
1614 		[COMPONENT_CACHE_INODE_LRU] = {
1615 			.comp_name = "COMPONENT_CACHE_INODE_LRU",
1616 			.comp_str = "INODE LRU",},
1617 		[COMPONENT_HASHTABLE] = {
1618 			.comp_name = "COMPONENT_HASHTABLE",
1619 			.comp_str = "HT",},
1620 		[COMPONENT_HASHTABLE_CACHE] = {
1621 			.comp_name = "COMPONENT_HASHTABLE_CACHE",
1622 			.comp_str = "HT CACHE",},
1623 		[COMPONENT_DUPREQ] = {
1624 			.comp_name = "COMPONENT_DUPREQ",
1625 			.comp_str = "DUPREQ",},
1626 		[COMPONENT_INIT] = {
1627 			.comp_name = "COMPONENT_INIT",
1628 			.comp_str = "NFS STARTUP",},
1629 		[COMPONENT_MAIN] = {
1630 			.comp_name = "COMPONENT_MAIN",
1631 			.comp_str = "MAIN",},
1632 		[COMPONENT_IDMAPPER] = {
1633 			.comp_name = "COMPONENT_IDMAPPER",
1634 			.comp_str = "ID MAPPER",},
1635 		[COMPONENT_NFS_READDIR] = {
1636 			.comp_name = "COMPONENT_NFS_READDIR",
1637 			.comp_str = "NFS READDIR",},
1638 		[COMPONENT_NFS_V4_LOCK] = {
1639 			.comp_name = "COMPONENT_NFS_V4_LOCK",
1640 			.comp_str = "NFS4 LOCK",},
1641 		[COMPONENT_CONFIG] = {
1642 			.comp_name = "COMPONENT_CONFIG",
1643 			.comp_str = "CONFIG",},
1644 		[COMPONENT_CLIENTID] = {
1645 			.comp_name = "COMPONENT_CLIENTID",
1646 			.comp_str = "CLIENT ID",},
1647 		[COMPONENT_SESSIONS] = {
1648 			.comp_name = "COMPONENT_SESSIONS",
1649 			.comp_str = "SESSIONS",},
1650 		[COMPONENT_PNFS] = {
1651 			.comp_name = "COMPONENT_PNFS",
1652 			.comp_str = "PNFS",},
1653 		[COMPONENT_RW_LOCK] = {
1654 			.comp_name = "COMPONENT_RW_LOCK",
1655 			.comp_str = "RW LOCK",},
1656 		[COMPONENT_NLM] = {
1657 			.comp_name = "COMPONENT_NLM",
1658 			.comp_str = "NLM",},
1659 		[COMPONENT_RPC] = {
1660 			.comp_name = "COMPONENT_RPC",
1661 			.comp_str = "RPC",},
1662 		[COMPONENT_TIRPC] = {
1663 			.comp_name = "COMPONENT_TIRPC",
1664 			.comp_str = "TIRPC",},
1665 		[COMPONENT_NFS_CB] = {
1666 			.comp_name = "COMPONENT_NFS_CB",
1667 			.comp_str = "NFS CB",},
1668 		[COMPONENT_THREAD] = {
1669 			.comp_name = "COMPONENT_THREAD",
1670 			.comp_str = "THREAD",},
1671 		[COMPONENT_NFS_V4_ACL] = {
1672 			.comp_name = "COMPONENT_NFS_V4_ACL",
1673 			.comp_str = "NFS4 ACL",},
1674 		[COMPONENT_STATE] = {
1675 			.comp_name = "COMPONENT_STATE",
1676 			.comp_str = "STATE",},
1677 		[COMPONENT_9P] = {
1678 			.comp_name = "COMPONENT_9P",
1679 			.comp_str = "9P",},
1680 		[COMPONENT_9P_DISPATCH] = {
1681 			.comp_name = "COMPONENT_9P_DISPATCH",
1682 			.comp_str = "9P DISP",},
1683 		[COMPONENT_FSAL_UP] = {
1684 			.comp_name = "COMPONENT_FSAL_UP",
1685 			.comp_str = "FSAL_UP",},
1686 		[COMPONENT_DBUS] = {
1687 			.comp_name = "COMPONENT_DBUS",
1688 			.comp_str = "DBUS",},
1689 		[COMPONENT_NFS_MSK] = {
1690 			.comp_name = "COMPONENT_NFS_MSK",
1691 			.comp_str = "NFS_MSK",}
1692 	};
1693 	
1694 	void DisplayLogComponentLevel(log_components_t component, const char *file,
1695 				int line, const char *function, log_levels_t level,
1696 				const char *format, ...)
1697 	{
1698 		va_list arguments;
1699 	
1700 		va_start(arguments, format);
1701 	
1702 		display_log_component_level(component, file, line, function, level,
1703 					    format, arguments);
1704 	
1705 		va_end(arguments);
1706 	}
1707 	
1708 	void LogMallocFailure(const char *file, int line, const char *function,
1709 			      const char *allocator)
1710 	{
1711 		DisplayLogComponentLevel(COMPONENT_MEM_ALLOC, (char *) file, line,
1712 					 (char *)function, NIV_NULL,
1713 					 "Aborting %s due to out of memory",
1714 					 allocator);
1715 	}
1716 	
1717 	/*
1718 	 *  Re-export component logging to TI-RPC internal logging
1719 	 */
1720 	void rpc_warnx(char *fmt, ...)
1721 	{
1722 		va_list ap;
1723 	
1724 		if (component_log_level[COMPONENT_TIRPC] <= NIV_FATAL)
1725 			return;
1726 	
1727 		va_start(ap, fmt);
1728 	
1729 		display_log_component_level(COMPONENT_TIRPC, "<no-file>", 0, "rpc",
1730 					    component_log_level[COMPONENT_TIRPC],
1731 					    fmt, ap);
1732 	
1733 		va_end(ap);
1734 	
1735 	}
1736 	
1737 	#ifdef USE_DBUS
1738 	
1739 	static bool dbus_prop_get(log_components_t component, DBusMessageIter *reply)
1740 	{
1741 		char *level_code;
1742 	
1743 		level_code = ReturnLevelInt(component_log_level[component]);
1744 		if (level_code == NULL)
1745 			return false;
1746 		if (!dbus_message_iter_append_basic
1747 		    (reply, DBUS_TYPE_STRING, &level_code))
1748 			return false;
1749 		return true;
1750 	}
1751 	
1752 	static bool dbus_prop_set(log_components_t component, DBusMessageIter *arg)
1753 	{
1754 		char *level_code;
1755 		int log_level;
1756 	
1757 		if (dbus_message_iter_get_arg_type(arg) != DBUS_TYPE_STRING)
1758 			return false;
1759 		dbus_message_iter_get_basic(arg, &level_code);
1760 		log_level = ReturnLevelAscii(level_code);
1761 		if (log_level == -1) {
1762 			LogDebug(COMPONENT_DBUS,
1763 				 "Invalid log level: '%s' given for component %s",
1764 				 level_code, LogComponents[component].comp_name);
1765 			return false;
1766 		}
1767 	
1768 		if (component == COMPONENT_ALL) {
1769 			_SetLevelDebug(log_level);
1770 			LogChanges("Dbus set log level for all components to %s",
1771 				   level_code);
1772 		} else {
1773 			LogChanges("Dbus set log level for %s from %s to %s.",
1774 				   LogComponents[component].comp_name,
1775 				   ReturnLevelInt(component_log_level[component]),
1776 				   ReturnLevelInt(log_level));
1777 			SetComponentLogLevel(component, log_level);
1778 		}
1779 		return true;
1780 	}
1781 	
1782 	/* Macros to make mapping properties table to components enum etc. easier
1783 	 * expands to table entries and shim functions.
1784 	 */
1785 	
1786 	#define HANDLE_PROP(component) \
1787 	static bool dbus_prop_get_COMPONENT_##component(DBusMessageIter *reply) \
1788 	{ \
1789 		return dbus_prop_get(COMPONENT_##component, reply);\
1790 	} \
1791 	\
1792 	static bool dbus_prop_set_COMPONENT_##component(DBusMessageIter *args) \
1793 	{ \
1794 		return dbus_prop_set(COMPONENT_##component, args);\
1795 	} \
1796 	\
1797 	static struct gsh_dbus_prop COMPONENT_##component##_prop = {	\
1798 		.name = "COMPONENT_" #component,			\
1799 		.access = DBUS_PROP_READWRITE,				\
1800 		.type =  "s",						\
1801 		.get = dbus_prop_get_COMPONENT_##component,		\
1802 		.set = dbus_prop_set_COMPONENT_##component		\
1803 	}
1804 	
1805 	#define LOG_PROPERTY_ITEM(component) (&COMPONENT_##component##_prop)
1806 	
1807 	/**
1808 	 * @brief Log property handlers.
1809 	 *
1810 	 * Expands to get/set functions that match dbus_prop_get/set protos
1811 	 * and call common handler with component enum as arg.
1812 	 * There is one line per log_components_t enum.
1813 	 * These must also match LOG_PROPERTY_ITEM
1814 	 */
1815 	
1816 	HANDLE_PROP(ALL);
1817 	HANDLE_PROP(LOG);
1818 	HANDLE_PROP(MEM_ALLOC);
1819 	HANDLE_PROP(MEMLEAKS);
1820 	HANDLE_PROP(FSAL);
1821 	HANDLE_PROP(NFSPROTO);
1822 	HANDLE_PROP(NFS_V4);
1823 	HANDLE_PROP(EXPORT);
1824 	HANDLE_PROP(FILEHANDLE);
1825 	HANDLE_PROP(DISPATCH);
1826 	HANDLE_PROP(CACHE_INODE);
1827 	HANDLE_PROP(CACHE_INODE_LRU);
1828 	HANDLE_PROP(HASHTABLE);
1829 	HANDLE_PROP(HASHTABLE_CACHE);
1830 	HANDLE_PROP(DUPREQ);
1831 	HANDLE_PROP(INIT);
1832 	HANDLE_PROP(MAIN);
1833 	HANDLE_PROP(IDMAPPER);
1834 	HANDLE_PROP(NFS_READDIR);
1835 	HANDLE_PROP(NFS_V4_LOCK);
1836 	HANDLE_PROP(CONFIG);
1837 	HANDLE_PROP(CLIENTID);
1838 	HANDLE_PROP(SESSIONS);
1839 	HANDLE_PROP(PNFS);
1840 	HANDLE_PROP(RW_LOCK);
1841 	HANDLE_PROP(NLM);
1842 	HANDLE_PROP(RPC);
1843 	HANDLE_PROP(TIRPC);
1844 	HANDLE_PROP(NFS_CB);
1845 	HANDLE_PROP(THREAD);
1846 	HANDLE_PROP(NFS_V4_ACL);
1847 	HANDLE_PROP(STATE);
1848 	HANDLE_PROP(9P);
1849 	HANDLE_PROP(9P_DISPATCH);
1850 	HANDLE_PROP(FSAL_UP);
1851 	HANDLE_PROP(DBUS);
1852 	HANDLE_PROP(NFS_MSK);
1853 	
1854 	static struct gsh_dbus_prop *log_props[] = {
1855 		LOG_PROPERTY_ITEM(ALL),
1856 		LOG_PROPERTY_ITEM(LOG),
1857 		LOG_PROPERTY_ITEM(MEM_ALLOC),
1858 		LOG_PROPERTY_ITEM(MEMLEAKS),
1859 		LOG_PROPERTY_ITEM(FSAL),
1860 		LOG_PROPERTY_ITEM(NFSPROTO),
1861 		LOG_PROPERTY_ITEM(NFS_V4),
1862 		LOG_PROPERTY_ITEM(EXPORT),
1863 		LOG_PROPERTY_ITEM(FILEHANDLE),
1864 		LOG_PROPERTY_ITEM(DISPATCH),
1865 		LOG_PROPERTY_ITEM(CACHE_INODE),
1866 		LOG_PROPERTY_ITEM(CACHE_INODE_LRU),
1867 		LOG_PROPERTY_ITEM(HASHTABLE),
1868 		LOG_PROPERTY_ITEM(HASHTABLE_CACHE),
1869 		LOG_PROPERTY_ITEM(DUPREQ),
1870 		LOG_PROPERTY_ITEM(INIT),
1871 		LOG_PROPERTY_ITEM(MAIN),
1872 		LOG_PROPERTY_ITEM(IDMAPPER),
1873 		LOG_PROPERTY_ITEM(NFS_READDIR),
1874 		LOG_PROPERTY_ITEM(NFS_V4_LOCK),
1875 		LOG_PROPERTY_ITEM(CONFIG),
1876 		LOG_PROPERTY_ITEM(CLIENTID),
1877 		LOG_PROPERTY_ITEM(SESSIONS),
1878 		LOG_PROPERTY_ITEM(PNFS),
1879 		LOG_PROPERTY_ITEM(RW_LOCK),
1880 		LOG_PROPERTY_ITEM(NLM),
1881 		LOG_PROPERTY_ITEM(RPC),
1882 		LOG_PROPERTY_ITEM(TIRPC),
1883 		LOG_PROPERTY_ITEM(NFS_CB),
1884 		LOG_PROPERTY_ITEM(THREAD),
1885 		LOG_PROPERTY_ITEM(NFS_V4_ACL),
1886 		LOG_PROPERTY_ITEM(STATE),
1887 		LOG_PROPERTY_ITEM(9P),
1888 		LOG_PROPERTY_ITEM(9P_DISPATCH),
1889 		LOG_PROPERTY_ITEM(FSAL_UP),
1890 		LOG_PROPERTY_ITEM(DBUS),
1891 		LOG_PROPERTY_ITEM(NFS_MSK),
1892 		NULL
1893 	};
1894 	
1895 	struct gsh_dbus_interface log_interface = {
1896 		.name = "org.ganesha.nfsd.log.component",
1897 		.signal_props = false,
1898 		.props = log_props,
1899 		.methods = NULL,
1900 		.signals = NULL
1901 	};
1902 	
1903 	#endif				/* USE_DBUS */
1904 	
1905 	enum facility_state {
1906 		FAC_IDLE,
1907 		FAC_ACTIVE,
1908 		FAC_DEFAULT
1909 	};
1910 	
1911 	struct facility_config {
1912 		struct glist_head fac_list;
1913 		char *facility_name;
1914 		char *dest;
1915 		enum facility_state state;
1916 		lf_function_t *func;
1917 		log_header_t headers;
1918 		log_levels_t max_level;
1919 		void *lf_private;
1920 	};
1921 	
1922 	/**
1923 	 * @brief Logger config block parameters
1924 	 */
1925 	
1926 	struct logger_config {
1927 		struct glist_head facility_list;
1928 		struct logfields *logfields;
1929 		log_levels_t *comp_log_level;
1930 		log_levels_t default_level;
1931 		uint32_t rpc_debug_flags;
1932 	};
1933 	
1934 	/**
1935 	 * @brief Enumerated time and date format parameters
1936 	 */
1937 	
1938 	static struct config_item_list timeformats[] = {
1939 		CONFIG_LIST_TOK("ganesha", TD_GANESHA),
1940 		CONFIG_LIST_TOK("true", TD_GANESHA),
1941 		CONFIG_LIST_TOK("local", TD_LOCAL),
1942 		CONFIG_LIST_TOK("8601", TD_8601),
1943 		CONFIG_LIST_TOK("ISO-8601", TD_8601),
1944 		CONFIG_LIST_TOK("ISO 8601", TD_8601),
1945 		CONFIG_LIST_TOK("ISO", TD_8601),
1946 		CONFIG_LIST_TOK("syslog", TD_SYSLOG),
1947 		CONFIG_LIST_TOK("syslog_usec", TD_SYSLOG_USEC),
1948 		CONFIG_LIST_TOK("false", TD_NONE),
1949 		CONFIG_LIST_TOK("none", TD_NONE),
1950 		CONFIG_LIST_TOK("user_defined", TD_USER),
1951 		CONFIG_LIST_EOL
1952 	};
1953 	
1954 	/**
1955 	 * @brief Logging format parameters
1956 	 */
1957 	
1958 	static struct config_item format_options[] = {
1959 		CONF_ITEM_TOKEN("date_format", TD_GANESHA, timeformats,
1960 				logfields, datefmt),
1961 		CONF_ITEM_TOKEN("time_format", TD_GANESHA, timeformats,
1962 				logfields, timefmt),
1963 		CONF_ITEM_STR("user_date_format", 1, MAX_TD_FMT_LEN, NULL,
1964 			       logfields, user_date_fmt),
1965 		CONF_ITEM_STR("user_time_format", 1, MAX_TD_FMT_LEN, NULL,
1966 			       logfields, user_time_fmt),
1967 		CONF_ITEM_BOOL("EPOCH", true,
1968 			       logfields, disp_epoch),
1969 		CONF_ITEM_BOOL("CLIENTIP", false,
1970 			       logfields, disp_clientip),
1971 		CONF_ITEM_BOOL("HOSTNAME", true,
1972 			       logfields, disp_host),
1973 		CONF_ITEM_BOOL("PROGNAME", true,
1974 			       logfields, disp_prog),
1975 		CONF_ITEM_BOOL("PID", true,
1976 			       logfields, disp_pid),
1977 		CONF_ITEM_BOOL("THREAD_NAME", true,
1978 			       logfields, disp_threadname),
1979 		CONF_ITEM_BOOL("FILE_NAME", true,
1980 			       logfields, disp_filename),
1981 		CONF_ITEM_BOOL("LINE_NUM", true,
1982 			       logfields, disp_linenum),
1983 		CONF_ITEM_BOOL("FUNCTION_NAME", true,
1984 			       logfields, disp_funct),
1985 		CONF_ITEM_BOOL("COMPONENT", true,
1986 			       logfields, disp_comp),
1987 		CONF_ITEM_BOOL("LEVEL", true,
1988 			       logfields, disp_level),
1989 		CONFIG_EOL
1990 	};
1991 	
1992 	/**
1993 	 * @brief Initialize the log message format parameters
1994 	 */
1995 	
1996 	static void *format_init(void *link_mem, void *self_struct)
1997 	{
1998 		assert(link_mem != NULL || self_struct != NULL);
1999 	
2000 		if (link_mem == NULL)
2001 			return NULL;
2002 		if (self_struct == NULL)
2003 			return gsh_calloc(1, sizeof(struct logfields));
2004 		else {
2005 			struct logfields *lf = self_struct;
2006 	
2007 			if (lf->user_date_fmt != NULL)
2008 				gsh_free(lf->user_date_fmt);
2009 			if (lf->user_time_fmt != NULL)
2010 				gsh_free(lf->user_time_fmt);
2011 			gsh_free(lf);
2012 			return NULL;
2013 		}
2014 	}
2015 	
2016 	/**
2017 	 * @brief Commit the log format parameters
2018 	 *
2019 	 * I'd prefer that Date_format and Time_format be enums but they are not.
2020 	 * They are enums except when they are not and we do hope that whatever
2021 	 * that is can be digested by printf...
2022 	 */
2023 	
2024 	static int format_commit(void *node, void *link_mem, void *self_struct,
2025 				 struct config_error_type *err_type)
2026 	{
2027 		struct logfields *log = (struct logfields *)self_struct;
2028 		struct logfields **logp = link_mem;
2029 		struct logger_config *logger;
2030 		int errcnt = 0;
2031 	
2032 		if (log->datefmt == TD_USER && log->user_date_fmt == NULL) {
2033 			LogCrit(COMPONENT_CONFIG,
2034 				"Date is \"user_set\" with empty date format.");
2035 			err_type->validate = true;
2036 			errcnt++;
2037 		}
2038 		if (log->datefmt != TD_USER && log->user_date_fmt != NULL) {
2039 			LogCrit(COMPONENT_CONFIG,
2040 				"Set user date format (%s) but not \"user_set\" format",
2041 				log->user_date_fmt);
2042 			err_type->validate = true;
2043 			errcnt++;
2044 		}
2045 		if (log->timefmt == TD_USER && log->user_time_fmt == NULL) {
2046 			LogCrit(COMPONENT_CONFIG,
2047 				"Time is \"user_set\" with empty time format.");
2048 			err_type->validate = true;
2049 			errcnt++;
2050 		}
2051 		if (log->timefmt != TD_USER && log->user_time_fmt != NULL) {
2052 			LogCrit(COMPONENT_CONFIG,
2053 				"Set time format string (%s) but not \"user_set\" format",
2054 				log->user_time_fmt);
2055 			err_type->validate = true;
2056 			errcnt++;
2057 		}
2058 		if (errcnt == 0) {
2059 			logger = container_of(logp, struct logger_config, logfields);
2060 			logger->logfields = log;
2061 		}
2062 		return errcnt;
2063 	}
2064 	
2065 	/**
2066 	 * @brief Log component levels
2067 	 */
2068 	
2069 	static struct config_item_list log_levels[] = {
2070 		CONFIG_LIST_TOK("NULL", NIV_NULL),
2071 		CONFIG_LIST_TOK("FATAL", NIV_FATAL),
2072 		CONFIG_LIST_TOK("MAJ", NIV_MAJ),
2073 		CONFIG_LIST_TOK("CRIT", NIV_CRIT),
2074 		CONFIG_LIST_TOK("WARN", NIV_WARN),
2075 		CONFIG_LIST_TOK("EVENT", NIV_EVENT),
2076 		CONFIG_LIST_TOK("INFO", NIV_INFO),
2077 		CONFIG_LIST_TOK("DEBUG", NIV_DEBUG),
2078 		CONFIG_LIST_TOK("MID_DEBUG", NIV_MID_DEBUG),
2079 		CONFIG_LIST_TOK("M_DBG", NIV_MID_DEBUG),
2080 		CONFIG_LIST_TOK("FULL_DEBUG", NIV_FULL_DEBUG),
2081 		CONFIG_LIST_TOK("F_DBG", NIV_FULL_DEBUG),
2082 		CONFIG_LIST_EOL
2083 	};
2084 	
2085 	/**
2086 	 * @brief Logging components
2087 	 */
2088 	static struct config_item component_levels[] = {
2089 		CONF_INDEX_TOKEN("ALL", NB_LOG_LEVEL, log_levels,
2090 				 COMPONENT_ALL, int),
2091 		CONF_INDEX_TOKEN("LOG", NB_LOG_LEVEL, log_levels,
2092 				 COMPONENT_LOG, int),
2093 		CONF_INDEX_TOKEN("MEM_ALLOC", NB_LOG_LEVEL, log_levels,
2094 				 COMPONENT_MEM_ALLOC, int),
2095 		CONF_INDEX_TOKEN("MEMLEAKS", NB_LOG_LEVEL, log_levels,
2096 				 COMPONENT_MEMLEAKS, int),
2097 		CONF_INDEX_TOKEN("LEAKS", NB_LOG_LEVEL, log_levels,
2098 				 COMPONENT_MEMLEAKS, int),
2099 		CONF_INDEX_TOKEN("FSAL", NB_LOG_LEVEL, log_levels,
2100 				 COMPONENT_FSAL, int),
2101 		CONF_INDEX_TOKEN("NFSPROTO", NB_LOG_LEVEL, log_levels,
2102 				 COMPONENT_NFSPROTO, int),
2103 		CONF_INDEX_TOKEN("NFS3", NB_LOG_LEVEL, log_levels,
2104 				 COMPONENT_NFSPROTO, int),
2105 		CONF_INDEX_TOKEN("NFS_V4", NB_LOG_LEVEL, log_levels,
2106 				 COMPONENT_NFS_V4, int),
2107 		CONF_INDEX_TOKEN("NFS4", NB_LOG_LEVEL, log_levels,
2108 				 COMPONENT_NFS_V4, int),
2109 		CONF_INDEX_TOKEN("EXPORT", NB_LOG_LEVEL, log_levels,
2110 				 COMPONENT_EXPORT, int),
2111 		CONF_INDEX_TOKEN("FILEHANDLE", NB_LOG_LEVEL, log_levels,
2112 				 COMPONENT_FILEHANDLE, int),
2113 		CONF_INDEX_TOKEN("FH", NB_LOG_LEVEL, log_levels,
2114 				 COMPONENT_FILEHANDLE, int),
2115 		CONF_INDEX_TOKEN("DISPATCH", NB_LOG_LEVEL, log_levels,
2116 				 COMPONENT_DISPATCH, int),
2117 		CONF_INDEX_TOKEN("DISP", NB_LOG_LEVEL, log_levels,
2118 				 COMPONENT_DISPATCH, int),
2119 		CONF_INDEX_TOKEN("CACHE_INODE", NB_LOG_LEVEL, log_levels,
2120 				 COMPONENT_CACHE_INODE, int),
2121 		CONF_INDEX_TOKEN("INODE", NB_LOG_LEVEL, log_levels,
2122 				 COMPONENT_CACHE_INODE, int),
2123 		CONF_INDEX_TOKEN("CACHE_INODE_LRU", NB_LOG_LEVEL, log_levels,
2124 				 COMPONENT_CACHE_INODE_LRU, int),
2125 		CONF_INDEX_TOKEN("INODE_LRU", NB_LOG_LEVEL, log_levels,
2126 				 COMPONENT_CACHE_INODE_LRU, int),
2127 		CONF_INDEX_TOKEN("HASHTABLE", NB_LOG_LEVEL, log_levels,
2128 				 COMPONENT_HASHTABLE, int),
2129 		CONF_INDEX_TOKEN("HT", NB_LOG_LEVEL, log_levels,
2130 				 COMPONENT_HASHTABLE, int),
2131 		CONF_INDEX_TOKEN("HASHTABLE_CACHE", NB_LOG_LEVEL, log_levels,
2132 				 COMPONENT_HASHTABLE_CACHE, int),
2133 		CONF_INDEX_TOKEN("HT_CACHE", NB_LOG_LEVEL, log_levels,
2134 				 COMPONENT_HASHTABLE_CACHE, int),
2135 		CONF_INDEX_TOKEN("DUPREQ", NB_LOG_LEVEL, log_levels,
2136 				 COMPONENT_DUPREQ, int),
2137 		CONF_INDEX_TOKEN("INIT", NB_LOG_LEVEL, log_levels,
2138 				 COMPONENT_INIT, int),
2139 		CONF_INDEX_TOKEN("NFS_STARTUP", NB_LOG_LEVEL, log_levels,
2140 				 COMPONENT_INIT, int),
2141 		CONF_INDEX_TOKEN("MAIN", NB_LOG_LEVEL, log_levels,
2142 				 COMPONENT_MAIN, int),
2143 		CONF_INDEX_TOKEN("IDMAPPER", NB_LOG_LEVEL, log_levels,
2144 				 COMPONENT_IDMAPPER, int),
2145 		CONF_INDEX_TOKEN("NFS_READDIR", NB_LOG_LEVEL, log_levels,
2146 				 COMPONENT_NFS_READDIR, int),
2147 		CONF_INDEX_TOKEN("NFS_V4_LOCK", NB_LOG_LEVEL, log_levels,
2148 				 COMPONENT_NFS_V4_LOCK, int),
2149 		CONF_INDEX_TOKEN("NFS4_LOCK", NB_LOG_LEVEL, log_levels,
2150 				 COMPONENT_NFS_V4_LOCK, int),
2151 		CONF_INDEX_TOKEN("CONFIG", NB_LOG_LEVEL, log_levels,
2152 				 COMPONENT_CONFIG, int),
2153 		CONF_INDEX_TOKEN("CLIENTID", NB_LOG_LEVEL, log_levels,
2154 				 COMPONENT_CLIENTID, int),
2155 		CONF_INDEX_TOKEN("SESSIONS", NB_LOG_LEVEL, log_levels,
2156 				 COMPONENT_SESSIONS, int),
2157 		CONF_INDEX_TOKEN("PNFS", NB_LOG_LEVEL, log_levels,
2158 				 COMPONENT_PNFS, int),
2159 		CONF_INDEX_TOKEN("RW_LOCK", NB_LOG_LEVEL, log_levels,
2160 				 COMPONENT_RW_LOCK, int),
2161 		CONF_INDEX_TOKEN("NLM", NB_LOG_LEVEL, log_levels,
2162 				 COMPONENT_NLM, int),
2163 		CONF_INDEX_TOKEN("RPC", NB_LOG_LEVEL, log_levels,
2164 				 COMPONENT_RPC, int),
2165 		CONF_INDEX_TOKEN("TIRPC", NB_LOG_LEVEL, log_levels,
2166 				 COMPONENT_TIRPC, int),
2167 		CONF_INDEX_TOKEN("NFS_CB", NB_LOG_LEVEL, log_levels,
2168 				 COMPONENT_NFS_CB, int),
2169 		CONF_INDEX_TOKEN("THREAD", NB_LOG_LEVEL, log_levels,
2170 				 COMPONENT_THREAD, int),
2171 		CONF_INDEX_TOKEN("NFS_V4_ACL", NB_LOG_LEVEL, log_levels,
2172 				 COMPONENT_NFS_V4_ACL, int),
2173 		CONF_INDEX_TOKEN("NFS4_ACL", NB_LOG_LEVEL, log_levels,
2174 				 COMPONENT_NFS_V4_ACL, int),
2175 		CONF_INDEX_TOKEN("STATE", NB_LOG_LEVEL, log_levels,
2176 				 COMPONENT_STATE, int),
2177 		CONF_INDEX_TOKEN("_9P", NB_LOG_LEVEL, log_levels,
2178 				 COMPONENT_9P, int),
2179 		CONF_INDEX_TOKEN("_9P_DISPATCH", NB_LOG_LEVEL, log_levels,
2180 				 COMPONENT_9P_DISPATCH, int),
2181 		CONF_INDEX_TOKEN("_9P_DISP", NB_LOG_LEVEL, log_levels,
2182 				 COMPONENT_9P_DISPATCH, int),
2183 		CONF_INDEX_TOKEN("FSAL_UP", NB_LOG_LEVEL, log_levels,
2184 				 COMPONENT_FSAL_UP, int),
2185 		CONF_INDEX_TOKEN("DBUS", NB_LOG_LEVEL, log_levels,
2186 				 COMPONENT_DBUS, int),
2187 		CONF_INDEX_TOKEN("NFS_MSK", NB_LOG_LEVEL, log_levels,
2188 				 COMPONENT_NFS_MSK, int),
2189 		CONFIG_EOL
2190 	};
2191 	
2192 	/**
2193 	 * @brief Initialize the log level array
2194 	 *
2195 	 * We allocate an array here even for the global case so as to
2196 	 * preserve something that works (default_log_levels) during config
2197 	 * processing.  If the parse errors out, we just throw it away...
2198 	 *
2199 	 */
2200 	
2201 	static void *component_init(void *link_mem, void *self_struct)
2202 	{
2203 		assert(link_mem != NULL || self_struct != NULL);
2204 	
2205 		if (link_mem == NULL)
2206 			return NULL;
2207 		if (self_struct == NULL)
2208 			return gsh_calloc(COMPONENT_COUNT, sizeof(log_levels_t));
2209 		else {
2210 			gsh_free(self_struct);
2211 			return NULL;
2212 		}
2213 	}
2214 	
2215 	/**
2216 	 * @brief Commit the component levels
2217 	 *
2218 	 * COMPONENT_ALL is a magic component.  It gets statically initialized
2219 	 * to NIV_NULL (no output) but the initialize pass changes that to
2220 	 * NB_LOG_LEVEL which is +1 the last valid level. This is used to detect
2221 	 * if COMPONENT_ALL has been set.  If ALL is set, it overrides all
2222 	 * components including any that were set in the block.
2223 	 *
2224 	 * We also set the default for all components to be NB_LOG_LEVELS which
2225 	 * gets changed to the LOG { default_log_level ...} or NIV_EVENT if it
2226 	 * was not changed by the config.
2227 	 */
2228 	
2229 	static int component_commit(void *node, void *link_mem, void *self_struct,
2230 				    struct config_error_type *err_type)
2231 	{
2232 		log_levels_t **log_lvls = link_mem;
2233 		struct logger_config *logger;
2234 		log_levels_t *log_level = self_struct;
2235 	
2236 		if (log_level[COMPONENT_ALL] != NB_LOG_LEVEL) {
2237 			SetLevelDebug(log_level[COMPONENT_ALL]);
2238 		} else {
2239 			int comp;
2240 	
2241 			logger = container_of(log_lvls,
2242 					      struct logger_config,
2243 					      comp_log_level);
2244 			if (logger->default_level == NB_LOG_LEVEL)
2245 				logger->default_level = NIV_EVENT;
2246 			for (comp = COMPONENT_LOG; comp < COMPONENT_COUNT; comp++)
2247 				if (log_level[comp] == NB_LOG_LEVEL)
2248 					log_level[comp] = logger->default_level;
2249 			log_level[COMPONENT_ALL] = NIV_NULL;
2250 			logger->comp_log_level = log_level;
2251 		}
2252 		return 0;
2253 	}
2254 	
2255 	static struct config_item_list header_options[] = {
2256 		CONFIG_LIST_TOK("none", LH_NONE),
2257 		CONFIG_LIST_TOK("component", LH_COMPONENT),
2258 		CONFIG_LIST_TOK("all", LH_ALL),
2259 		CONFIG_LIST_EOL
2260 	};
2261 	
2262 	static struct config_item_list enable_options[] = {
2263 		CONFIG_LIST_TOK("idle", FAC_IDLE),
2264 		CONFIG_LIST_TOK("active", FAC_ACTIVE),
2265 		CONFIG_LIST_TOK("default", FAC_DEFAULT),
2266 		CONFIG_LIST_EOL
2267 	};
2268 	
2269 	static struct config_item facility_params[] = {
2270 		CONF_ITEM_STR("name", 1, 20, NULL,
2271 			      facility_config, facility_name),
2272 		CONF_MAND_STR("destination", 1, MAXPATHLEN, NULL,
2273 			      facility_config, dest),
2274 		CONF_ITEM_TOKEN("max_level", NB_LOG_LEVEL, log_levels,
2275 				facility_config, max_level),
2276 		CONF_ITEM_TOKEN("headers", NB_LH_TYPES, header_options,
2277 				facility_config, headers),
2278 		CONF_ITEM_TOKEN("enable", FAC_IDLE, enable_options,
2279 				facility_config, state),
2280 		CONFIG_EOL
2281 	};
2282 	
2283 	/**
2284 	 * @brief Initialize a Facility block.
2285 	 *
2286 	 * This block is allocated just to capture the fields.  It's members
2287 	 * are used to create/modify a facility at which point it gets freed.
2288 	 */
2289 	
2290 	static void *facility_init(void *link_mem, void *self_struct)
2291 	{
2292 		struct facility_config *facility;
2293 	
2294 		assert(link_mem != NULL || self_struct != NULL);
2295 	
2296 		if (link_mem == NULL) {
2297 			struct glist_head *facility_list;
2298 			struct logger_config *logger;
2299 	
2300 			facility_list = self_struct;
2301 			logger = container_of(facility_list,
2302 					      struct logger_config,
2303 					      facility_list);
2304 			glist_init(&logger->facility_list);
2305 			return self_struct;
2306 		} else if (self_struct == NULL) {
2307 			facility = gsh_calloc(1, sizeof(struct facility_config));
2308 			return facility;
2309 		} else {
2310 			facility = self_struct;
2311 	
2312 			assert(glist_null(&facility->fac_list));
2313 	
2314 			if (facility->facility_name != NULL)
2315 				gsh_free(facility->facility_name);
2316 			if (facility->dest != NULL)
2317 				gsh_free(facility->dest);
2318 			gsh_free(self_struct);
2319 		}
2320 		return NULL;
2321 	}
2322 	
2323 	/**
2324 	 * @brief Commit a facility block
2325 	 *
2326 	 * It can create a stream, syslog, or file facility and modify any
2327 	 * existing one.  Special loggers must be created elsewhere.
2328 	 * Note that you cannot use a log { facility {... }} to modify one
2329 	 * of these special loggers because log block parsing is done first
2330 	 * at server initialization.
2331 	 */
2332 	
2333 	static int facility_commit(void *node, void *link_mem, void *self_struct,
2334 				   struct config_error_type *err_type)
2335 	{
2336 		struct facility_config *conf = self_struct;
2337 		struct glist_head *fac_list;
2338 		int errcnt = 0;
2339 	
2340 		if (conf->facility_name == NULL) {
2341 			LogCrit(COMPONENT_LOG,
2342 				"No facility name given");
2343 			err_type->missing = true;
2344 			errcnt++;
2345 			return errcnt;
2346 		}
2347 		if (conf->dest != NULL) {
2348 			if (strcasecmp(conf->dest, "stderr") == 0) {
2349 				conf->func = log_to_stream;
2350 				conf->lf_private = stderr;
2351 				if (conf->headers == NB_LH_TYPES)
2352 					conf->headers = LH_ALL;
2353 			} else if (strcasecmp(conf->dest, "stdout") == 0) {
2354 				conf->func = log_to_stream;
2355 				conf->lf_private = stdout;
2356 				if (conf->headers == NB_LH_TYPES)
2357 					conf->headers = LH_ALL;
2358 			} else if (strcasecmp(conf->dest, "syslog") == 0) {
2359 				conf->func = log_to_syslog;
2360 				if (conf->headers == NB_LH_TYPES)
2361 					conf->headers = LH_COMPONENT;
2362 			} else {
2363 				conf->func = log_to_file;
2364 				conf->lf_private = conf->dest;
2365 				if (conf->headers == NB_LH_TYPES)
2366 					conf->headers = LH_ALL;
2367 			}
2368 		} else {
2369 			LogCrit(COMPONENT_LOG,
2370 				"No facility destination given for (%s)",
2371 				conf->facility_name);
2372 			err_type->missing = true;
2373 			errcnt++;
2374 			return errcnt;
2375 		}
2376 		if (conf->func != log_to_syslog && conf->headers < LH_ALL)
2377 			LogWarn(COMPONENT_CONFIG,
2378 				"Headers setting for %s could drop some format fields!",
2379 				conf->facility_name);
2380 		if (conf->max_level == NB_LOG_LEVEL)
2381 			conf->max_level = NIV_FULL_DEBUG;
2382 		fac_list = link_mem;
2383 		glist_add_tail(fac_list, &conf->fac_list);
2384 		return 0;
2385 	}
2386 	
2387 	static void *log_conf_init(void *link_mem, void *self_struct)
2388 	{
2389 		struct logger_config *logger = self_struct;
2390 	
2391 		assert(link_mem != NULL || self_struct != NULL);
2392 	
2393 		if (link_mem == NULL)
2394 			return self_struct;
2395 		else if (self_struct == NULL)
2396 			return link_mem;
2397 		else {
2398 			if (logger->comp_log_level) {
2399 				(void)component_init(&logger->comp_log_level,
2400 						     logger->comp_log_level);
2401 				logger->comp_log_level = NULL;
2402 			}
2403 			if (!glist_empty(&logger->facility_list)) {
2404 				struct glist_head *glist, *glistn;
2405 	
2406 				glist_for_each_safe(glist, glistn,
2407 						    &logger->facility_list) {
2408 					struct facility_config *conf;
2409 	
2410 					conf = glist_entry(glist,
2411 							   struct facility_config,
2412 							   fac_list);
2413 					glist_del(&conf->fac_list);
2414 					(void)facility_init(&logger->facility_list,
2415 							    conf);
2416 				}
2417 			}
2418 			if (logger->logfields != NULL) {
2419 				(void)format_init(&logger->logfields,
2420 						  logger->logfields);
2421 				logger->logfields = NULL;
2422 			}
2423 		}
2424 		return NULL;
2425 	}
2426 	
2427 	static int log_conf_commit(void *node, void *link_mem, void *self_struct,
2428 				   struct config_error_type *err_type)
2429 	{
2430 		struct logger_config *logger = self_struct;
2431 		struct glist_head *glist, *glistn;
2432 		int errcnt = 0;
2433 		int rc;
2434 	
2435 		glist_for_each_safe(glist, glistn, &logger->facility_list) {
2436 			struct facility_config *conf;
2437 			bool facility_exists;
2438 	
2439 			conf = glist_entry(glist, struct facility_config, fac_list);
2440 			glist_del(&conf->fac_list);
2441 			if (errcnt) {
2442 				LogEvent(COMPONENT_CONFIG,
2443 					 "Skipping facility (%s) due to errors",
2444 					 conf->facility_name);
2445 				goto done;
2446 			}
2447 			rc = create_log_facility(conf->facility_name,
2448 						 conf->func,
2449 						 conf->max_level,
2450 						 conf->headers,
2451 						 conf->lf_private);
2452 			if (rc != 0 && rc != -EEXIST) {
2453 				LogCrit(COMPONENT_CONFIG,
2454 					"Failed to create facility (%s), (%s)",
2455 					conf->facility_name,
2456 					strerror(-rc));
2457 				err_type->resource = true;
2458 				errcnt++;
2459 				goto done;
2460 			}
2461 			facility_exists = (rc == -EEXIST);
2462 			if (facility_exists && conf->dest != NULL) {
2463 				rc = set_log_destination(conf->facility_name,
2464 							 conf->dest);
2465 				if (rc < 0) {
2466 					LogCrit(COMPONENT_LOG,
2467 						"Could not set destination for (%s) because (%s)",
2468 						conf->facility_name,
2469 						strerror(-rc));
2470 					err_type->resource = true;
2471 					errcnt++;
2472 					goto done;
2473 				}
2474 			}
2475 			if (facility_exists && conf->max_level != NB_LOG_LEVEL) {
2476 				rc =  set_log_level(conf->facility_name,
2477 						    conf->max_level);
2478 				if (rc < 0)  {
2479 					LogCrit(COMPONENT_LOG,
2480 						"Could not set severity level for (%s) because (%s)",
2481 						conf->facility_name,
2482 						strerror(-rc));
2483 					err_type->resource = true;
2484 					errcnt++;
2485 					goto done;
2486 				}
2487 			}
2488 			if (conf->state == FAC_ACTIVE) {
2489 				rc = enable_log_facility(conf->facility_name);
2490 				if (rc != 0) {
2491 					LogCrit(COMPONENT_CONFIG,
2492 						"Could not enable (%s) because (%s)",
2493 						conf->facility_name,
2494 						strerror(-rc));
2495 					err_type->resource = true;
2496 					errcnt++;
2497 				}
2498 			} else if (conf->state == FAC_DEFAULT) {
2499 				struct log_facility *old_def
2500 					= default_facility;
2501 	
2502 				rc = set_default_log_facility(conf->facility_name);
2503 				if (rc != 0) {
2504 					LogCrit(COMPONENT_CONFIG,
2505 						"Could not make (%s) the default because (%s)",
2506 						conf->facility_name,
2507 						strerror(-rc));
2508 					err_type->resource = true;
2509 					errcnt++;
2510 				} else if (old_def != default_facility)
2511 					LogEvent(COMPONENT_CONFIG,
2512 						 "Switched default logger from %s to %s",
2513 						 old_def->lf_name,
2514 						 default_facility->lf_name);
2515 			}
2516 			if (errcnt > 0 && !facility_exists) {
2517 				LogCrit(COMPONENT_CONFIG,
2518 					"Releasing new logger (%s) because of errors",
2519 					conf->facility_name);
2520 				release_log_facility(conf->facility_name);
2521 			}
2522 	 done:
2523 			(void)facility_init(&logger->facility_list, conf);
2524 		}
2525 		if (errcnt == 0) {
2526 			if (logger->logfields != NULL) {
2527 				LogEvent(COMPONENT_CONFIG,
2528 					 "Changing definition of log fields");
2529 				if (logfields != &default_logfields) {
2530 					if (logfields->user_date_fmt != NULL)
2531 						gsh_free(logfields->user_date_fmt);
2532 					if (logfields->user_time_fmt != NULL)
2533 						gsh_free(logfields->user_time_fmt);
2534 					gsh_free(logfields);
2535 				}
2536 				logfields = logger->logfields;
2537 	
2538 				/* rebuild const_log_str with new format params. */
2539 				set_const_log_str();
2540 			}
2541 			if (logger->comp_log_level != NULL) {
2542 				LogEvent(COMPONENT_CONFIG,
2543 					 "Switching to new component log levels");
2544 				if (component_log_level != default_log_levels)
2545 					gsh_free(component_log_level);
2546 				component_log_level = logger->comp_log_level;
2547 			}
2548 			ntirpc_pp.debug_flags = logger->rpc_debug_flags;
2549 			SetNTIRPCLogLevel(component_log_level[COMPONENT_TIRPC]);
2550 		} else {
2551 			if (logger->logfields != NULL) {
2552 				struct logfields *lf = logger->logfields;
2553 	
2554 				if (lf->user_date_fmt != NULL)
2555 					gsh_free(lf->user_date_fmt);
2556 				if (lf->user_time_fmt != NULL)
2557 					gsh_free(lf->user_time_fmt);
2558 				gsh_free(lf);
2559 			}
2560 			if (logger->comp_log_level != NULL)
2561 				gsh_free(logger->comp_log_level);
2562 		}
2563 		logger->logfields = NULL;
2564 		logger->comp_log_level = NULL;
2565 		return errcnt;
2566 	}
2567 	
2568 	static struct config_item logging_params[] = {
2569 		CONF_ITEM_TOKEN("Default_log_level", NB_LOG_LEVEL, log_levels,
2570 				 logger_config, default_level),
2571 		CONF_ITEM_UI32("RPC_Debug_Flags", 0, UINT32_MAX,
2572 			       TIRPC_DEBUG_FLAG_DEFAULT,
2573 			       logger_config, rpc_debug_flags),
2574 		CONF_ITEM_BLOCK("Facility", facility_params,
2575 				facility_init, facility_commit,
2576 				logger_config, facility_list),
2577 		CONF_ITEM_BLOCK("Format", format_options,
2578 				format_init, format_commit,
2579 				logger_config, logfields),
2580 		CONF_ITEM_BLOCK("Components", component_levels,
2581 				component_init, component_commit,
2582 				logger_config, comp_log_level),
2583 		CONFIG_EOL
2584 	};
2585 	
2586 	struct config_block logging_param = {
2587 		.dbus_interface_name = "org.ganesha.nfsd.config.log",
2588 		.blk_desc.name = "LOG",
2589 		.blk_desc.type = CONFIG_BLOCK,
2590 		.blk_desc.flags = CONFIG_UNIQUE,  /* too risky to have more */
2591 		.blk_desc.u.blk.init = log_conf_init,
2592 		.blk_desc.u.blk.params = logging_params,
2593 		.blk_desc.u.blk.commit = log_conf_commit
2594 	};
2595 	
2596 	/**
2597 	 *
2598 	 * @brief Process the config parse tree for the logging component.
2599 	 *
2600 	 * Switch from the default component levels only if we found one
2601 	 * @param in_config [IN] configuration file handle
2602 	 *
2603 	 * @return 0 if ok, -1 if failed,
2604 	 *
2605 	 */
2606 	int read_log_config(config_file_t in_config,
2607 			    struct config_error_type *err_type)
2608 	{
2609 		struct logger_config logger;
2610 	
2611 		memset(&logger, 0, sizeof(struct logger_config));
2612 		(void)load_config_from_parse(in_config,
2613 					     &logging_param,
2614 					     &logger,
2615 					     true,
2616 					     err_type);
2617 		if (config_error_is_harmless(err_type))
2618 			return 0;
2619 		else
2620 			return -1;
2621 	}				/* read_log_config */
2622 	
2623 	void gsh_backtrace(void)
2624 	{
2625 	#define MAX_STACK_DEPTH		32	/* enough ? */
2626 		void *buffer[MAX_STACK_DEPTH];
2627 		struct log_facility *facility;
2628 		struct glist_head *glist;
2629 		int fd = -1;
2630 		char **traces;
2631 		int i, nlines;
2632 	
2633 		nlines = backtrace(buffer, MAX_STACK_DEPTH);
2634 	
2635 		/* Find an active log facility that is file based to
2636 		 * log the backtrace symbols.
2637 		 */
2638 		PTHREAD_RWLOCK_rdlock(&log_rwlock);
2639 		glist_for_each(glist, &active_facility_list) {
2640 			facility = glist_entry(glist, struct log_facility, lf_active);
2641 			if (facility->lf_func == log_to_file) {
2642 				fd = open((char *)facility->lf_private,
2643 					  O_WRONLY | O_APPEND | O_CREAT, log_mask);
2644 				break;
2645 			}
2646 		}
2647 	
2648 		if (fd != -1) {
2649 			LogMajor(COMPONENT_INIT, "stack backtrace follows:");
2650 			backtrace_symbols_fd(buffer, nlines, fd);
2651 			close(fd);
2652 		} else {
2653 			/* No file based logging, hope malloc call inside
2654 			 * backtrace_symbols() doesn't hang!
2655 			 */
2656 			traces = backtrace_symbols(buffer, nlines);
2657 			if (traces) {
2658 				for (i = 0; i < nlines; i++) {
2659 					LogMajor(COMPONENT_INIT, "%s", traces[i]);
2660 				}
2661 				free(traces);
2662 			}
2663 		}
2664 		PTHREAD_RWLOCK_unlock(&log_rwlock);
2665 	}
2666