lease file -> XML?

Phil Benchoff benchoff at vt.edu
Mon Aug 30 14:38:20 UTC 2004


Below is a README and current version of the patch I posted about last week.
In addition to the replies that were posted on dhcp-hackers, I did receive
replies from two other folks who expressed some interest.

This patch is used to dump an XML version of some things in the leases file
and I am using it to get the status of the running server.   If there is
interest in getting this into the distribution, I will try to get the
patch into reasonable shape to do so.

Phil

------------------------------------------------------------

README file for patches to output lease file in XML.

Description

This patch adds a command-line option (-lx) to ISC dhcpd.  The -lx option
causes dhcpd to output an XML version of the lease file to stdout.

Caveats

- This patch is not useful for the dhcpd server itself.  I suggest not
  changing the dhcpd you use in production and just building a stand-alone
  dhcpd to use to parse the lease file.
  NOTE:  DUE TO A SEGFAULT I HAVEN'T HAD TIME TO DEAL WITH, THE PATCHED
  VERSION CAN'T BE USED AS A SERVER.
- Do not run this as a user that can write to the lease database.
- The XML output should be well-formed, but I have not written a formal
  specification and don't plan to at the moment.
- I have only tested it on Linux so far.  I suspect there are issues
  with the printing of longs that may pop up on 64-bit platforms.
- Not all elements of leases are output.
- There is no code to output group and host declarations at the moment.
- I use tab stops at 4-character spacing.  I'll clean up my indenting to
  match the rest of the code if this patch goes anywhere.

Patching

In the root of the ISC DHCP distribution:

    patch --verbose -b -p1 < dhcp-3.0-xml-parser-patch

Compilation

Add "--copts -DVT_PARSER_ONLY" to whatever options you use with the
configure command.  Be sure you see "-DVT_PARSER_ONLY" on the CC commands
as the program compiles.  "-lx" should appear in the usage output of the
dhcpd program.

Installation

This patch does not add any functionality to the dhcpd server and I suggest
using the dhcpd produced here as a stand-alone program and not changing the
dhcpd you actually use as a server.

Usage

Just add the -lx and -q options to dhcpd.  If you normally use -cf, you
will need it here too.

TODO

Soon:
- create or find a function properly escape CDATA
- fix output so only XML goes to stdout, errors to stderr, and don't
  do any syslogging.
- make sure exit code is 0 for success and non-zero for errors
- host and group data: either output as XML or be sure it is bypassed

Maybe:
- command-line options for IP address range, binding states, and
  hardware addresses.
- develop XML schema/DTD or whatever
 
=========================================================================
Under the Hood
=========================================================================

This patch was developed on ISC dhcp-3.0.1 with no other patches.

All code should be encapsulated in #ifdef VT_PARSER_ONLY/#endif.

The code path is similar to what is used with the -T option (test
lease file, lftest global) except that expire_all_pools() and
write_leases() are called.  write_xxx() functions in db.c are modified
to output XML conditional on lfxml.

server/dhcpd.c:
  - add lfxml global that keeps track of whether we should output XML
  - add -lf command line option
  - add !lfxml to the conditional for starting ICMP support.  This will
    probably be removed since lftest is set with -lx.
  - add -lf to the usage

server/mdb.c:
  - add extern lfxml declaration
  - changed write_leases() to output XML
  - comment out call to pool_timer() in exipre_all_pools()

server/db.c:
  - add extern lfxml declaration
  - db_startup() function changed to call expire_all_pools(), set db_file
    to stdout, and call write_leases() if lfxml is set.
  - write_(lease|failover_state|<etc>) functions  changed to output XML
  - new_lease_file() changed to call log_fatal() if lfxml is set.
    (This needs to be handled better.)

Phil Benchoff, benchoff at vt.edu
$Id: README.xml,v 1.5 2004/08/30 13:06:17 benchoff Exp $
------------------------------------------------------------

--- dhcp-3.0.1-OEM/server/dhcpd.c	2004-07-09 20:11:18.000000000 -0400
+++ dhcp-3.0.1+vt_parser/server/dhcpd.c	2004-08-30 08:33:21.000000000 -0400
@@ -153,6 +153,11 @@
 
 int dhcp_max_agent_option_packet_length = DHCP_MTU_MAX;
 
+#ifdef VT_PARSER_ONLY
+/* Keeps track of -lx option */
+int lfxml = 0;
+#endif
+
 static omapi_auth_key_t *omapi_key = (omapi_auth_key_t *)0;
 int omapi_port;
 
@@ -317,6 +322,16 @@
 			cftest = 1;
 			lftest = 1;
 			log_perror = -1;
+#ifdef VT_PARSER_ONLY
+		} else if (!strcmp (argv [i], "-lx")) {
+			/* output lease file XML */
+			cftest = 1;
+			lftest = 1;
+			lfxml = 1;
+#ifndef DEBUG
+			daemon = 0;
+#endif
+#endif /* VTPARSER_ONLY */
 		} else if (!strcmp (argv [i], "-q")) {
 			quiet = 1;
 			quiet_interface_discovery = 1;
@@ -875,7 +890,11 @@
 	log_info (copyright);
 	log_info (arr);
 
+#ifdef VT_PARSER_ONLY
+	log_fatal ("Usage: dhcpd [-p <UDP port #>] [-d] [-f]%s%s%s%s%s",
+#else
 	log_fatal ("Usage: dhcpd [-p <UDP port #>] [-d] [-f]%s%s%s%s",
+#endif
 		   "\n             [-cf config-file] [-lf lease-file]",
 #if defined (TRACING)
 		   "\n		   [-tf trace-output-file]",
@@ -883,7 +902,12 @@
 #else
 		   "", "",
 #endif /* TRACING */
-		   "\n             [-t] [-T] [-s server] [if0 [...ifN]]");
+		   "\n             [-t] [-T] [-s server] [if0 [...ifN]]",
+#ifdef VT_PARSER_ONLY
+		   "\n             [-lx]");
+#else
+			"");
+#endif
 }
 
 void lease_pinged (from, packet, length)
--- dhcp-3.0.1-OEM/server/mdb.c	2004-06-10 13:59:56.000000000 -0400
+++ dhcp-3.0.1+vt_parser/server/mdb.c	2004-08-30 08:41:48.000000000 -0400
@@ -40,6 +40,10 @@
 #include "dhcpd.h"
 #include "omapip/hash.h"
 
+#ifdef VT_PARSER_ONLY
+extern int lfxml;
+#endif
+
 struct subnet *subnets;
 struct shared_network *shared_networks;
 host_hash_t *host_hw_addr_hash;
@@ -1738,6 +1742,12 @@
 	int num_written;
 	struct lease **lptr [5];
 
+#ifdef VT_PARSER_ONLY
+	if ( lfxml ) {
+		fputs("<dhcp_server>\n",stdout);
+	}
+#endif
+
 	/* Write all the dynamically-created group declarations. */
 	if (group_name_hash) {
 	    num_written = 0;
@@ -1795,10 +1805,25 @@
 
 #if defined (FAILOVER_PROTOCOL)
 	/* Write all the failover states. */
+#ifdef VT_PARSER_ONLY
+	if ( lfxml ) {
+		fputs("  <failover_states>\n",stdout);
+	}
+#endif
 	if (!dhcp_failover_write_all_states ())
 		return 0;
+#ifdef VT_PARSER_ONLY
+	if ( lfxml ) {
+		fputs("  </failover_states>\n",stdout);
+	}
+#endif
 #endif
 
+#ifdef VT_PARSER_ONLY
+	if ( lfxml ) {
+		fputs("  <leases>\n",stdout);
+	}
+#endif
 	/* Write all the leases. */
 	num_written = 0;
 	for (s = shared_networks; s; s = s -> next) {
@@ -1825,7 +1850,18 @@
 		}
 	    }
 	}
+#ifdef VT_PARSER_ONLY
+	if ( lfxml ) {
+		fputs("  </leases>\n",stdout);
+	}
+#endif
 	log_info ("Wrote %d leases to leases file.", num_written);
+#ifdef VT_PARSER_ONLY
+	if ( lfxml ) {
+		fputs("</dhcp_server>\n",stdout);
+		return 0;
+	}
+#endif
 	if (!commit_leases ())
 		return 0;
 	return 1;
@@ -1973,7 +2009,18 @@
 	   expiry routine on the pool. */
 	for (s = shared_networks; s; s = s -> next) {
 	    for (p = s -> pools; p; p = p -> next) {
+#ifdef VT_PARSER_ONLY
+/*
+ * XXX N3PB
+ * Segfaults in here sometimes.  This doesn't seem to be
+ * critical to getting a reasolable XML output.  Until
+ * this is taken care of, the binary generated can't
+ * be used as a real DHCP server.
+#endif
 		pool_timer (p);
+#ifdef VT_PARSER_ONLY
+ */
+#endif
 
 		p -> lease_count = 0;
 		p -> free_leases = 0;
--- dhcp-3.0.1-OEM/server/db.c	2004-06-17 16:54:40.000000000 -0400
+++ dhcp-3.0.1+vt_parser/server/db.c	2004-08-30 08:39:00.000000000 -0400
@@ -48,6 +48,10 @@
 TIME write_time;
 int lease_file_is_corrupt = 0;
 
+#ifdef VT_PARSER_ONLY
+extern int lfxml;
+#endif
+
 /* Write the specified lease to the current lease database file. */
 
 int write_lease (lease)
@@ -69,7 +73,23 @@
 	if (counting)
 		++count;
 	errno = 0;
-	fprintf (db_file, "lease %s {", piaddr (lease -> ip_addr));
+#ifdef VT_PARSER_ONLY
+	if ( lfxml ) {
+		/*
+		 * lease->ip_addr is 16 bytes.
+		 * use ISC function to convert to dotted-decimal string
+		 * convert with inet_addr
+		 * print with ntohl
+		 */
+		fprintf (stdout,"    <lease id=\"%u\">\n",ntohl(inet_addr(piaddr (lease -> ip_addr))));
+		fprintf (stdout,"      <address family=\"inet\" ip_integer=\"%u\">%s</address>\n",
+					ntohl(inet_addr(piaddr (lease -> ip_addr))),piaddr (lease -> ip_addr));
+	} else {
+#endif
+		fprintf (db_file, "lease %s {", piaddr (lease -> ip_addr));
+#ifdef VT_PARSER_ONLY
+	}
+#endif
 	if (errno) {
 		++errors;
 	}
@@ -88,7 +108,15 @@
 		} else
 			strcpy (tbuf, "never;");
 		errno = 0;
-		fprintf (db_file, "\n  starts %s", tbuf);
+#ifdef VT_PARSER_ONLY
+		if ( lfxml ) {
+			fprintf(stdout,"      <start time=\"%u\">%s</start>\n",lease -> starts,tbuf);
+		} else {
+#endif
+			fprintf (db_file, "\n  starts %s", tbuf);
+#ifdef VT_PARSER_ONLY
+		}
+#endif
 		if (errno) {
 			++errors;
 		}
@@ -105,7 +133,15 @@
 		} else
 			strcpy (tbuf, "never;");
 		errno = 0;
-		fprintf (db_file, "\n  ends %s", tbuf);
+#ifdef VT_PARSER_ONLY
+		if ( lfxml ) {
+			fprintf(stdout,"      <end time=\"%u\">%s</end>\n",lease -> ends,tbuf);
+		} else {
+#endif
+			fprintf (db_file, "\n  ends %s", tbuf);
+#ifdef VT_PARSER_ONLY
+		}
+#endif
 		if (errno) {
 			++errors;
 		}
@@ -114,10 +150,18 @@
 	if (lease -> tstp) {
 		t = gmtime (&lease -> tstp);
 		errno = 0;
-		fprintf (db_file, "\n  tstp %d %d/%02d/%02d %02d:%02d:%02d;",
-			 t -> tm_wday, t -> tm_year + 1900,
-			 t -> tm_mon + 1, t -> tm_mday,
-			 t -> tm_hour, t -> tm_min, t -> tm_sec);
+#ifdef VT_PARSER_ONLY
+		if ( lfxml ) {
+		} else {
+#endif
+			fprintf (db_file, "\n  tstp %d %d/%02d/%02d %02d:%02d:%02d;",
+				 t -> tm_wday, t -> tm_year + 1900,
+				 t -> tm_mon + 1, t -> tm_mday,
+				 t -> tm_hour, t -> tm_min, t -> tm_sec);
+#ifdef VT_PARSER_ONLY
+		}
+#endif
+
 		if (errno) {
 			++errors;
 		}
@@ -125,10 +169,17 @@
 	if (lease -> tsfp) {
 		t = gmtime (&lease -> tsfp);
 		errno = 0;
+#ifdef VT_PARSER_ONLY
+		if ( lfxml ) {
+		} else {
+#endif
 		fprintf (db_file, "\n  tsfp %d %d/%02d/%02d %02d:%02d:%02d;",
 			 t -> tm_wday, t -> tm_year + 1900,
 			 t -> tm_mon + 1, t -> tm_mday,
 			 t -> tm_hour, t -> tm_min, t -> tm_sec);
+#ifdef VT_PARSER_ONLY
+		}
+#endif
 		if (errno) {
 			++errors;
 		}
@@ -136,10 +187,17 @@
 	if (lease -> cltt) {
 		t = gmtime (&lease -> cltt);
 		errno = 0;
+#ifdef VT_PARSER_ONLY
+		if ( lfxml ) {
+		} else {
+#endif
 		fprintf (db_file, "\n  cltt %d %d/%02d/%02d %02d:%02d:%02d;",
 			 t -> tm_wday, t -> tm_year + 1900,
 			 t -> tm_mon + 1, t -> tm_mday,
 			 t -> tm_hour, t -> tm_min, t -> tm_sec);
+#ifdef VT_PARSER_ONLY
+		}
+#endif
 		if (errno) {
 			++errors;
 		}
@@ -147,45 +205,106 @@
 
 	if (lease -> binding_state == FTS_ACTIVE &&
 	    (lease -> flags & BOOTP_LEASE)) {
-		fprintf (db_file, "\n  binding state bootp;\n");
+#ifdef VT_PARSER_ONLY
+		if ( lfxml ) {
+			fprintf (stdout,"      <binding_state type=\"current\" state=\"%s\" />\n","bootp");
+		} else {
+#endif
+			fprintf (db_file, "\n  binding state bootp;\n");
+#ifdef VT_PARSER_ONLY
+		}
+#endif
 	} else {
-		fprintf (db_file, "\n  binding state %s;",
-			 ((lease -> binding_state > 0 &&
-			   lease -> binding_state <= FTS_LAST)
-			  ? binding_state_names [lease -> binding_state - 1]
-			  : "abandoned"));
+#ifdef VT_PARSER_ONLY
+		if ( lfxml ) {
+			fprintf (stdout,"      <binding_state type=\"current\" state=\"%s\" />\n",
+				 ((lease -> binding_state > 0 &&
+				   lease -> binding_state <= FTS_LAST)
+				  ? binding_state_names [lease -> binding_state - 1]
+				  : "abandoned"));
+		} else {
+#endif
+			fprintf (db_file, "\n  binding state %s;",
+				 ((lease -> binding_state > 0 &&
+				   lease -> binding_state <= FTS_LAST)
+				  ? binding_state_names [lease -> binding_state - 1]
+				  : "abandoned"));
+#ifdef VT_PARSER_ONLY
+		}
+#endif
 	}
 
 	if (lease -> binding_state != lease -> next_binding_state) {
 	    if (lease -> next_binding_state == FTS_ACTIVE &&
-		(lease -> flags & BOOTP_LEASE))
-		fprintf (db_file, "\n  next binding state bootp;\n");
-	    else
-		fprintf (db_file, "\n  next binding state %s;",
-			 ((lease -> next_binding_state > 0 &&
-			   lease -> next_binding_state <= FTS_LAST)
-			  ? (binding_state_names
-			     [lease -> next_binding_state - 1])
-		  : "abandoned"));
+		(lease -> flags & BOOTP_LEASE)) {
+#ifdef VT_PARSER_ONLY
+			if ( lfxml ) {
+				fprintf (stdout,"      <binding_state type=\"next\" state=\"%s\" />\n","bootp");
+			} else {
+#endif
+				fprintf (db_file, "\n  next binding state bootp;\n");
+#ifdef VT_PARSER_ONLY
+			}
+#endif
+	    } else {
+#ifdef VT_PARSER_ONLY
+			if ( lfxml ) {
+				fprintf (stdout,"      <binding_state type=\"next\" state=\"%s\" />\n",
+					 ((lease -> next_binding_state > 0 &&
+					   lease -> next_binding_state <= FTS_LAST)
+					  ? (binding_state_names
+					     [lease -> next_binding_state - 1])
+			  		: "abandoned"));
+			} else {
+#endif
+				fprintf (db_file, "\n  next binding state %s;",
+					 ((lease -> next_binding_state > 0 &&
+					   lease -> next_binding_state <= FTS_LAST)
+					  ? (binding_state_names
+					     [lease -> next_binding_state - 1])
+			  		: "abandoned"));
+#ifdef VT_PARSER_ONLY
+			}
+#endif
+		}
 	}
 
 	/* If this lease is billed to a class and is still valid,
 	   write it out. */
 	if (lease -> billing_class && lease -> ends > cur_time) {
-		if (!write_billing_class (lease -> billing_class)) {
-			log_error ("unable to write class %s",
-				   lease -> billing_class -> name);
-			++errors;
+#ifdef VT_PARSER_ONLY
+		if ( lfxml ) {
+		} else {
+#endif
+			if (!write_billing_class (lease -> billing_class)) {
+				log_error ("unable to write class %s",
+					   lease -> billing_class -> name);
+				++errors;
+			}
+#ifdef VT_PARSER_ONLY
 		}
+#endif
 	}
 
 	if (lease -> hardware_addr.hlen) {
 		errno = 0;
-		fprintf (db_file, "\n  hardware %s %s;",
-			 hardware_types [lease -> hardware_addr.hbuf [0]],
-			 print_hw_addr (lease -> hardware_addr.hbuf [0],
-					lease -> hardware_addr.hlen - 1,
-					&lease -> hardware_addr.hbuf [1]));
+#ifdef VT_PARSER_ONLY
+		if (lfxml) {
+			fprintf (stdout,"      <hardware_address type=\"%s\" address=\"%s\" />\n",
+				 hardware_types [lease -> hardware_addr.hbuf [0]],
+				 print_hw_addr (lease -> hardware_addr.hbuf [0],
+						lease -> hardware_addr.hlen - 1,
+						&lease -> hardware_addr.hbuf [1]));
+		} else {
+#endif
+			fprintf (db_file, "\n  hardware %s %s;",
+				 hardware_types [lease -> hardware_addr.hbuf [0]],
+				 print_hw_addr (lease -> hardware_addr.hbuf [0],
+						lease -> hardware_addr.hlen - 1,
+						&lease -> hardware_addr.hbuf [1]));
+#ifdef VT_PARSER_ONLY
+		}
+#endif
 		if (errno) {
 			++errors;
 		}
@@ -194,13 +313,25 @@
 		int i;
 		s = quotify_buf (lease -> uid, lease -> uid_len, MDL);
 		if (s) {
-			fprintf (db_file, "\n  uid \"%s\";", s);
+#ifdef VT_PARSER_ONLY
+			if ( lfxml ) {
+				/*  XXX N3PB escape cdata */
+			} else {
+#endif
+				fprintf (db_file, "\n  uid \"%s\";", s);
+#ifdef VT_PARSER_ONLY
+			}
+#endif
 			if (errno)
 				++errors;
 			dfree (s, MDL);
 		} else
 			++errors;
 	}
+#ifdef VT_PARSER_ONLY
+if ( !lfxml ) {
+	/* XXX N3PB Just skip this whole section for now. */
+#endif
 	if (lease -> scope) {
 	    for (b = lease -> scope -> bindings; b; b = b -> next) {
 		if (!b -> value)
@@ -295,8 +426,20 @@
 		/* XXX */
 		fprintf (db_file, "\n  }");
 	}
+#ifdef VT_PARSER_ONLY
+}
+#endif
+
 	errno = 0;
-	fputs ("\n}\n", db_file);
+#ifdef VT_PARSER_ONLY
+	if ( lfxml ) {
+		fputs("    </lease>\n", stdout);
+	} else {
+#endif
+		fputs ("\n}\n", db_file);
+#ifdef VT_PARSER_ONLY
+	}
+#endif
 	if (errno) {
 		++errors;
 	}
@@ -533,42 +676,89 @@
 			return 0;
 
 	errno = 0;
-	fprintf (db_file, "\nfailover peer \"%s\" state {", state -> name);
+#ifdef VT_PARSER_ONLY
+	if ( lfxml ) {
+		fprintf (stdout,"    <failover_state partner=\"%s\">\n",state->name);
+	} else {
+#endif
+		fprintf (db_file, "\nfailover peer \"%s\" state {", state -> name);
+#ifdef VT_PARSER_ONLY
+	}
+#endif
 	if (errno)
 		++errors;
 
 	t = gmtime (&state -> me.stos);
 	errno = 0;
-	fprintf (db_file, "\n  my state %s at %d %d/%02d/%02d %02d:%02d:%02d;",
-		 /* Never record our state as "startup"! */
-		 (state -> me.state == startup
-		  ? dhcp_failover_state_name_print (state -> saved_state)
-		  : dhcp_failover_state_name_print (state -> me.state)),
-		 t -> tm_wday, t -> tm_year + 1900,
-		 t -> tm_mon + 1, t -> tm_mday,
-		 t -> tm_hour, t -> tm_min, t -> tm_sec);
+#ifdef VT_PARSER_ONLY
+	if ( lfxml ) {
+		fprintf (stdout,"      <my_state state=\"%s\" time=\"%u\"/>\n",
+			 		(state -> me.state == startup
+			  		? dhcp_failover_state_name_print (state -> saved_state)
+			 		 : dhcp_failover_state_name_print (state -> me.state)),
+					state -> me.stos);
+	} else {
+#endif
+		fprintf (db_file, "\n  my state %s at %d %d/%02d/%02d %02d:%02d:%02d;",
+			 /* Never record our state as "startup"! */
+			 (state -> me.state == startup
+			  ? dhcp_failover_state_name_print (state -> saved_state)
+			  : dhcp_failover_state_name_print (state -> me.state)),
+			 t -> tm_wday, t -> tm_year + 1900,
+			 t -> tm_mon + 1, t -> tm_mday,
+			 t -> tm_hour, t -> tm_min, t -> tm_sec);
+#ifdef VT_PARSER_ONLY
+	}
+#endif
 	if (errno)
 		++errors;
 
 	t = gmtime (&state -> partner.stos);
 	errno = 0;
-	fprintf (db_file,
-		 "\n  partner state %s at %d %d/%02d/%02d %02d:%02d:%02d;",
-		 dhcp_failover_state_name_print (state -> partner.state),
-		 t -> tm_wday, t -> tm_year + 1900,
-		 t -> tm_mon + 1, t -> tm_mday,
-		 t -> tm_hour, t -> tm_min, t -> tm_sec);
+#ifdef VT_PARSER_ONLY
+	if ( lfxml ) {
+		fprintf (stdout,"      <partner_state state=\"%s\" time=\"%u\"/>\n",
+			 		dhcp_failover_state_name_print (state -> partner.state),
+					state -> partner.stos);
+	} else {
+#endif
+		fprintf (db_file,
+			 "\n  partner state %s at %d %d/%02d/%02d %02d:%02d:%02d;",
+			 dhcp_failover_state_name_print (state -> partner.state),
+			 t -> tm_wday, t -> tm_year + 1900,
+			 t -> tm_mon + 1, t -> tm_mday,
+			 t -> tm_hour, t -> tm_min, t -> tm_sec);
+#ifdef VT_PARSER_ONLY
+	}
+#endif
 	if (errno)
 		++errors;
 
 	if (state -> i_am == secondary) {
 		errno = 0;
-		fprintf (db_file, "\n  mclt %ld;",
-			 (unsigned long)state -> mclt);
+#ifdef VT_PARSER_ONLY
+		if ( lfxml ) {
+			fprintf (stdout, "      <mclt seconds=\"%ld\"/>\n",
+				 (unsigned long)state -> mclt);
+		} else {
+#endif
+			fprintf (db_file, "\n  mclt %ld;",
+				 (unsigned long)state -> mclt);
+#ifdef VT_PARSER_ONLY
+		}
+#endif
 		if (errno)
 			++errors;
 	}
-	fprintf (db_file, "\n}\n");
+#ifdef VT_PARSER_ONLY
+	if ( lfxml ) {
+		fprintf (stdout,"    </failover_state>\n");
+	} else {
+#endif
+		fprintf (db_file, "\n}\n");
+#ifdef VT_PARSER_ONLY
+	}
+#endif
 	if (errno)
 		++errors;
 
@@ -758,6 +948,18 @@
 			GET_TIME (&write_time);
 		new_lease_file ();
 	}
+#ifdef VT_PARSER_ONLY
+	  else {
+		if ( lfxml ) {
+			/* expire_all_pools ends up calling write_lease sometimes. */
+			lfxml = 0;
+			expire_all_pools();
+			lfxml = 1;
+			db_file = stdout;
+			write_leases();
+		}
+	}
+#endif
 }
 
 int new_lease_file ()
@@ -767,6 +969,11 @@
 	TIME t;
 	int db_fd;
 
+#ifdef VT_PARSER_ONLY
+	if ( lfxml ) {
+		log_fatal("new_lease_file() called in parser only mode.");
+	}
+#endif
 	/* If we already have an open database, close it. */
 	if (db_file) {
 		fclose (db_file);


More information about the dhcp-hackers mailing list