From 833a1f54de2b4565e9603eed1eaa1980c8ac8d74 Mon Sep 17 00:00:00 2001
From: Masahide NAKAMURA <nakam@linux-ipv6.org>
Date: Sun, 11 Feb 2007 07:31:54 +0900
Subject: [DEBUG]: Support logging to file for debug message.

Add logging file option for debug message.
When this option is omitted the message will be shown at tty. Otherwise
the daemon will detach from tty but write the message to it.
---
 src/bul.c   |    6 +++---
 src/conf.c  |    8 +++++++-
 src/conf.h  |    1 +
 src/debug.c |   57 +++++++++++++++++++++++++++++++++++++++++++++++----------
 src/debug.h |   12 ++++++++++--
 src/gram.y  |    5 +++++
 src/hash.c  |    2 +-
 src/ipsec.c |   28 ++++++++++++++--------------
 src/main.c  |   22 +++++++++++++++++++---
 src/mn.c    |    4 ++--
 src/scan.l  |    1 +
 11 files changed, 110 insertions(+), 36 deletions(-)

diff --git a/src/bul.c b/src/bul.c
index 6799765..4e7ce71 100644
--- a/src/bul.c
+++ b/src/bul.c
@@ -146,7 +146,7 @@ void bul_update_timer(struct bulentry *bule)
 	struct timespec timer_expire;
 	tsadd(bule->delay, bule->lastsent, timer_expire);
 	dbg("Updating timer\n");
-	dump_bule(bule, sdbg);
+	dbg_func(bule, dump_bule);
 	add_task_abs(&timer_expire, &bule->tqe, bule->callback);
 }
 
@@ -190,7 +190,7 @@ int bul_add(struct bulentry *bule)
 	}
 	tsadd(bule->delay, bule->lastsent, timer_expire);
 	dbg("Adding bule\n");
-	dump_bule(bule, sdbg);
+	dbg_func(bule, dump_bule);
 	add_task_abs(&timer_expire, &bule->tqe, bule->callback);
 	return 0;
 home_bul_free:
@@ -236,7 +236,7 @@ void bul_delete(struct bulentry *bule)
 	while (bule->ext_cleanup)
 		bule->ext_cleanup(bule);
 	dbg("Deleting bule\n");
-	dump_bule(bule, sdbg);
+	dbg_func(bule, dump_bule);
 	free_bule(bule);
 }
 
diff --git a/src/conf.c b/src/conf.c
index 056a481..4b418ef 100644
--- a/src/conf.c
+++ b/src/conf.c
@@ -62,6 +62,7 @@ static void conf_usage(char *exec_name)
 #endif
 		"\n These options override values read from config file:\n"
 		"  -d <number>              Set debug level (0-10)\n"
+		"  -l <file>                Write debug log to <file> instead of stderr\n"
 		"  -C, --correspondent-node Node is CN\n"
 		"  -H, --home-agent         Node is HA\n"
 		"  -M, --mobile-node        Node is MN\n\n"
@@ -141,7 +142,7 @@ static int conf_cmdline(struct mip6_config *cfg, int argc, char **argv)
 	/* parse all other cmd line parameters than -c */
 	while (1) {
 		int idx, c;
-		c = getopt_long(argc, argv, "c:d:Vh?CMH", long_opts, &idx);
+		c = getopt_long(argc, argv, "c:d:l:Vh?CMH", long_opts, &idx);
 		if (c == -1) break;
 
 		switch (c) {
@@ -165,6 +166,9 @@ static int conf_cmdline(struct mip6_config *cfg, int argc, char **argv)
 		case 'd':
 			cfg->debug_level = atoi(optarg);
 			break;
+		case 'l':
+			cfg->debug_log_file = optarg;
+			break;
 		case 'C':
 			cfg->mip6_entity = MIP6_ENTITY_CN;
 			break;
@@ -267,6 +271,8 @@ void conf_show(struct mip6_config *c)
 #endif
 	dbg("mip6_entity = %u\n", c->mip6_entity);
 	dbg("debug_level = %u\n", c->debug_level);
+	dbg("debug_log_file = %s\n", (c->debug_log_file ? c->debug_log_file :
+				      "stderr"));
 	if (c->pmgr.so_path)
 		dbg("PolicyModulePath = %s\n", c->pmgr.so_path);
 	dbg("DefaultBindingAclPolicy = %u\n", c->DefaultBindingAclPolicy);
diff --git a/src/conf.h b/src/conf.h
index 6d6a1bf..96c36f3 100644
--- a/src/conf.h
+++ b/src/conf.h
@@ -17,6 +17,7 @@ struct mip6_config {
 #endif
 	unsigned int mip6_entity;
 	unsigned int debug_level;
+	char *debug_log_file;
 	struct pmgr_cb pmgr;
 	struct list_head net_ifaces;
 	struct list_head bind_acl;
diff --git a/src/debug.c b/src/debug.c
index 33cdcdd..4177982 100644
--- a/src/debug.c
+++ b/src/debug.c
@@ -34,7 +34,7 @@
 
 #include "debug.h"
 
-FILE *sdbg;
+static FILE *sdbg;
 
 static const char *dbg_strdate(char *str)
 {
@@ -69,14 +69,15 @@ void dbgprint(const char *fname, const char *fmt, ...)
  
         va_start(args, fmt);
         vsprintf(s, fmt, args);
+        va_end(args);
 
 	memset(stime, '\0', sizeof(stime));
-	fprintf(stderr, "%s ", dbg_strdate(stime));
+	fprintf(sdbg, "%s ", dbg_strdate(stime));
 
 	if (fname)
-		fprintf(stderr, "%s: ", fname);
-	fprintf(stderr, "%s", s);
-        va_end(args);
+		fprintf(sdbg, "%s: ", fname);
+	fprintf(sdbg, "%s", s);
+	fflush(sdbg);
 }
 
 void debug_print_buffer(const void *data, int len, const char *fname, 
@@ -88,12 +89,48 @@ void debug_print_buffer(const void *data, int len, const char *fname,
  
         va_start(args, fmt);
         vsprintf(s, fmt, args);
-        fprintf(stderr, "%s: %s", fname, s);
+        fprintf(sdbg, "%s: %s", fname, s);
         va_end(args);
 	for (i = 0; i < len; i++) { 
-		if (i % 16 == 0) fprintf(stderr, "\n%04x: ", i); 
-		fprintf(stderr, "%02x ", ((unsigned char *)data)[i]); 
+		if (i % 16 == 0) fprintf(sdbg, "\n%04x: ", i);
+		fprintf(sdbg, "%02x ", ((unsigned char *)data)[i]);
 	} 
-	fprintf(stderr, "\n\n"); 
-	
+	fprintf(sdbg, "\n\n");
+	fflush(sdbg);
+}
+
+void debug_print_func(void *arg, void (*func)(void *arg, void *stream))
+{
+	func(arg, sdbg);
+	fflush(sdbg);
+}
+
+int debug_open(const char *path)
+{
+	FILE *fp;
+
+	if (!path)
+		return -EINVAL;
+	if (sdbg && sdbg != stderr)
+		return -EALREADY;
+
+	fp = fopen(path, "a");
+	if (!fp)
+		return -errno;
+	sdbg = fp;
+
+	return 0;
+}
+
+void debug_close(void)
+{
+	if (sdbg && sdbg != stderr)
+		fclose(sdbg);
+	debug_init();
 }
+
+void debug_init(void)
+{
+	sdbg = stderr;
+}
+
diff --git a/src/debug.h b/src/debug.h
index fc0ea6c..dde22f2 100644
--- a/src/debug.h
+++ b/src/debug.h
@@ -5,21 +5,24 @@
 
 #include <stdio.h>
 
-extern FILE *sdbg;
-
 #ifdef MIP6_NDEBUG
 #define NDEBUG 1
 #define dbg(...)
 #define cdbg(...)
 #define dbg_buf(...)
+#define dbg_func(arg, func)
 #define BUG(x)
 #define pthread_dbg(x)
 #define TRACE
+static inline int debug_open(const char *path){ return 0; }
+static inline void debug_close(void){}
+static inline void debug_init(void){}
 #else
 #define dbg(...) dbgprint(__FUNCTION__, __VA_ARGS__)
 #define cdbg(...) dbgprint(NULL, __VA_ARGS__)
 #define dbg_buf(data, len, ...) \
 	debug_print_buffer(data, len, __FUNCTION__, __VA_ARGS__)
+#define dbg_func(arg, func) debug_print_func(arg, func)
 
 #define BUG(x) dbgprint("BUG", "%s %d %s\n", __FUNCTION__, __LINE__, x)
 #define TRACE dbgprint(__FUNCTION__, "%d\n", __LINE__)
@@ -28,6 +31,11 @@ void dbgprint(const char *fname, const char *fmt, ...);
 
 void debug_print_buffer(const void *data, int len, const char *fname,
 			const char *fmt, ...);
+void debug_print_func(void *arg, void (*func)(void *arg, void *stream));
+
+int debug_open(const char *path);
+void debug_close(void);
+void debug_init(void);
 
 #ifndef DEBUG_LOCKING
 
diff --git a/src/gram.y b/src/gram.y
index cad775b..a674d53 100644
--- a/src/gram.y
+++ b/src/gram.y
@@ -107,6 +107,7 @@ static void uerror(const char *fmt, ...) {
 
 %token		MIP6ENTITY
 %token		DEBUGLEVEL
+%token		DEBUGLOGFILE
 %token		DOROUTEOPTIMIZATIONCN
 %token		DOROUTEOPTIMIZATIONMN
 %token		HOMEADDRESS
@@ -194,6 +195,10 @@ topdef		: MIP6ENTITY mip6entity ';'
 		{
 			conf.debug_level = $2;
 		}
+		| DEBUGLOGFILE QSTRING ';'
+		{
+			conf.debug_log_file = $2;
+		}
 		| NONVOLATILEBINDINGCACHE BOOL ';'
 		{
 			conf.NonVolatileBindingCache = $2;
diff --git a/src/hash.c b/src/hash.c
index 9290cf6..1efedfc 100644
--- a/src/hash.c
+++ b/src/hash.c
@@ -185,7 +185,7 @@ int hash_add(const struct hash *h, void *data,
 	assert(peer_addr);
 
 	if ((new = (struct hash_entry *)malloc(sizeof(struct hash_entry))) == NULL) {
-		fprintf(stderr, "hash_add: out of memeory\n");
+		dbg("out of memeory\n");
 		return -ENOMEM;
 	}
 	new->our_addr = our_addr;
diff --git a/src/ipsec.c b/src/ipsec.c
index daf2956..7cb9190 100644
--- a/src/ipsec.c
+++ b/src/ipsec.c
@@ -125,20 +125,20 @@ static int xfrm_sendmigrate(struct xfrm_userpolicy_info *sp,
 	xpid.dir = sp->dir;
 
 #if 0
-	fprintf(stderr, "sel.family = %d\n", xpid.sel.family);
-	fprintf(stderr, "sel.saddr = %x:%x:%x:%x:%x:%x:%x:%x\n",
-		NIP6ADDR((struct in6_addr *)&xpid.sel.saddr));
-	fprintf(stderr, "sel.prefixlen_s = %d\n", xpid.sel.prefixlen_s);
-	fprintf(stderr, "sel.sport = %d\n", xpid.sel.sport);
-	fprintf(stderr, "sel.sport_mask = %d\n", xpid.sel.sport_mask);
-	fprintf(stderr, "sel.daddr = %x:%x:%x:%x:%x:%x:%x:%x\n",
-		NIP6ADDR((struct in6_addr *)&xpid.sel.daddr));
-	fprintf(stderr, "sel.prefixlen_d = %d\n", xpid.sel.prefixlen_d);
-	fprintf(stderr, "sel.dport = %d\n", xpid.sel.dport);
-	fprintf(stderr, "sel.dport_mask = %d\n", xpid.sel.dport_mask);
-	fprintf(stderr, "sel.proto = %d\n", xpid.sel.proto);
-	fprintf(stderr, "sel.ifindex = %d\n", xpid.sel.ifindex);
-	fprintf(stderr, "sel.user = %d\n", xpid.sel.user);
+	dbg("sel.family = %d\n", xpid.sel.family);
+	dbg("sel.saddr = %x:%x:%x:%x:%x:%x:%x:%x\n",
+	    NIP6ADDR((struct in6_addr *)&xpid.sel.saddr));
+	dbg("sel.prefixlen_s = %d\n", xpid.sel.prefixlen_s);
+	dbg("sel.sport = %d\n", xpid.sel.sport);
+	dbg("sel.sport_mask = %d\n", xpid.sel.sport_mask);
+	dbg("sel.daddr = %x:%x:%x:%x:%x:%x:%x:%x\n",
+	    NIP6ADDR((struct in6_addr *)&xpid.sel.daddr));
+	dbg("sel.prefixlen_d = %d\n", xpid.sel.prefixlen_d);
+	dbg("sel.dport = %d\n", xpid.sel.dport);
+	dbg("sel.dport_mask = %d\n", xpid.sel.dport_mask);
+	dbg("sel.proto = %d\n", xpid.sel.proto);
+	dbg("sel.ifindex = %d\n", xpid.sel.ifindex);
+	dbg("sel.user = %d\n", xpid.sel.user);
 #endif
 
 	addattr_l(&req.n, sizeof(req), XFRMA_POLICY,
diff --git a/src/main.c b/src/main.c
index 0769cde..f5b3b7e 100644
--- a/src/main.c
+++ b/src/main.c
@@ -80,6 +80,7 @@ static void terminate(void)
 	/* got SIGINT, cleanup and exit */
 	syslog(LOG_INFO, "terminated (SIGINT)");
 	dbg("got SIGINT, exiting\n");
+	debug_close();
 	pthread_exit(NULL);
 }
 
@@ -176,7 +177,7 @@ int main(int argc, char **argv)
 	int logflags = 0;
 	int ret = 1;
 
-	sdbg = stderr;
+	debug_init();
 
 	sigemptyset(&sigblock);
 	sigaddset(&sigblock, SIGHUP);
@@ -206,8 +207,21 @@ int main(int argc, char **argv)
 	if (conf.debug_level == 0)
 		daemon_start(1);
 	else {
-		dbg("%s started in debug mode, not detaching from terminal\n",
-		    PACKAGE_NAME);
+		/* if debugging with debug log file, detach from tty */
+		if (conf.debug_log_file) {
+			daemon_start(1);
+
+			ret = debug_open(conf.debug_log_file);
+			if (ret < 0) {
+				fprintf(stderr, "can't init debug log:%s\n",
+					strerror(-ret));
+				goto debug_failed;
+			}
+			dbg("%s started in debug mode\n", PACKAGE_NAME);
+		} else {
+			dbg("%s started in debug mode, not detaching from terminal\n",
+			    PACKAGE_NAME);
+		}
 		conf_show(&conf);
 	}
 
@@ -270,6 +284,8 @@ taskqueue_failed:
 	policy_cleanup();
 policy_failed:
 rr_cn_failed:
+	debug_close();
+debug_failed:
 #ifdef ENABLE_VT
 vt_failed:
 #endif
diff --git a/src/mn.c b/src/mn.c
index 1c4fb2b..6b3e88f 100644
--- a/src/mn.c
+++ b/src/mn.c
@@ -955,7 +955,7 @@ static void mn_recv_ba(const struct ip6_mh *mh, ssize_t len,
 	    NIP6ADDR(in->local_coa != NULL ? in->local_coa : &in6addr_any),
 	    ba->ip6mhba_status);
 	dbg("Dumping corresponding BULE\n");
-	dump_bule(bule, sdbg);
+	dbg_func(bule, dump_bule);
 	/* First check authenticator */
 	if (!(bule->flags & IP6_MH_BU_HOME) &&
 	    mn_chk_bauth(ba, len, &mh_opts, bule)) {
@@ -2254,7 +2254,7 @@ static void mn_recv_brr(const struct ip6_mh *mh, ssize_t len,
 		return;
 	}
 	dbg("Received BRR\n");
-	dump_bule(e, sdbg);
+	dbg_func(e, dump_bule);
 	clock_gettime(CLOCK_REALTIME, &now);
 
 	/* Do we need a binding?  */
diff --git a/src/scan.l b/src/scan.l
index 09a6524..9f5e530 100644
--- a/src/scan.l
+++ b/src/scan.l
@@ -85,6 +85,7 @@ HA				{ return MIP6HA; }
 CN				{ return MIP6CN; }
 MN				{ return MIP6MN; }
 DebugLevel			{ return DEBUGLEVEL; }
+DebugLogFile			{ return DEBUGLOGFILE; }
 DoRouteOptimizationCN		{ return DOROUTEOPTIMIZATIONCN; }
 DoRouteOptimizationMN		{ return DOROUTEOPTIMIZATIONMN; }
 HomeAddress			{ return HOMEADDRESS; }
-- 
1.5.0.3

