supported. This is a milestone in acheiving RFC 3925 "VIVSO" and
DHCPv6 support.
+- A new common (server or client) option, 'db-time-format local;', has
+ been added which prints the local time in /var/db/dhcpd.leases rather
+ than UTC. Thanks to a patch from Ken Lalonde.
+
Changes since 3.0.4
- A warning that host statements declared within subnet or shared-network
#ifndef lint
static char ocopyright[] =
-"$Id: dhclient.c,v 1.139 2006/06/01 20:23:16 dhankins Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n";
+"$Id: dhclient.c,v 1.140 2006/06/06 16:35:18 dhankins Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n";
#endif /* not lint */
#include "dhcpd.h"
pair *hash;
int errors = 0;
char *s;
+ const char *tval;
if (!rewrite) {
if (leases_written++ > 20) {
client, write_lease_option);
}
- /* Note: the following is not a Y2K bug - it's a Y1.9K bug. Until
- somebody invents a time machine, I think we can safely disregard
- it. */
- t = gmtime (&lease -> renewal);
- fprintf (leaseFile,
- " renew %d %d/%d/%d %02d:%02d:%02d;\n",
- t -> tm_wday, t -> tm_year + 1900,
- t -> tm_mon + 1, t -> tm_mday,
- t -> tm_hour, t -> tm_min, t -> tm_sec);
- if (errno != 0) {
+ tval = print_time(lease->renewal);
+ if (tval == NULL ||
+ fprintf(leaseFile, " renew %s\n", tval) < 0)
errors++;
- errno = 0;
- }
- t = gmtime (&lease -> rebind);
- fprintf (leaseFile,
- " rebind %d %d/%d/%d %02d:%02d:%02d;\n",
- t -> tm_wday, t -> tm_year + 1900,
- t -> tm_mon + 1, t -> tm_mday,
- t -> tm_hour, t -> tm_min, t -> tm_sec);
- if (errno != 0) {
+
+ tval = print_time(lease->rebind);
+ if (tval == NULL ||
+ fprintf(leaseFile, " rebind %s\n", tval) < 0)
errors++;
- errno = 0;
- }
- t = gmtime (&lease -> expiry);
- fprintf (leaseFile,
- " expire %d %d/%d/%d %02d:%02d:%02d;\n",
- t -> tm_wday, t -> tm_year + 1900,
- t -> tm_mon + 1, t -> tm_mday,
- t -> tm_hour, t -> tm_min, t -> tm_sec);
- if (errno != 0) {
+
+ tval = print_time(lease->expiry);
+ if (tval == NULL ||
+ fprintf(leaseFile, " expire %s\n", tval) < 0)
errors++;
- errno = 0;
- }
- fprintf (leaseFile, "}\n");
- if (errno != 0) {
+
+ if (fprintf(leaseFile, "}\n") < 0)
errors++;
- errno = 0;
- }
- fflush (leaseFile);
- if (errno != 0) {
+
+ if (fflush(leaseFile) != 0)
errors++;
- errno = 0;
- }
+
if (!errors && makesure) {
if (fsync (fileno (leaseFile)) < 0) {
log_info ("write_client_lease: %m");
#ifndef lint
static char copyright[] =
-"$Id: conflex.c,v 1.98 2006/06/01 20:23:17 dhankins Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n";
+"$Id: conflex.c,v 1.99 2006/06/06 16:35:18 dhankins Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n";
#endif /* not lint */
#include "dhcpd.h"
return CLTT;
break;
case 'd':
+ if (!strcasecmp(atom + 1, "b-time-format"))
+ return DB_TIME_FORMAT;
if (!strcasecmp (atom + 1, "ns-update"))
return DNS_UPDATE;
if (!strcasecmp (atom + 1, "ns-delete"))
}
if (!strcasecmp (atom + 1, "ncode-int"))
return ENCODE_INT;
+ if (!strcasecmp(atom + 1, "poch"))
+ return EPOCH;
if (!strcasecmp (atom + 1, "thernet"))
return ETHERNET;
if (!strcasecmp (atom + 1, "nds"))
return LET;
if (!strcasecmp (atom + 1, "oad"))
return LOAD;
+ if (!strcasecmp(atom + 1, "ocal"))
+ return LOCAL;
if (!strcasecmp (atom + 1, "og"))
return LOG;
break;
#ifndef lint
static char copyright[] =
-"$Id: parse.c,v 1.111 2006/06/05 16:42:58 dhankins Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n";
+"$Id: parse.c,v 1.112 2006/06/06 16:35:18 dhankins Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n";
#endif /* not lint */
#include "dhcpd.h"
return MAX_TIME;
}
+ /* This indicates 'local' time format. */
+ if (token == EPOCH) {
+ token = next_token(&val, NULL, cfile);
+
+ if (token != NUMBER) {
+ parse_warn(cfile, "Seconds since epoch expected.");
+ if (token != SEMI)
+ skip_to_semi(cfile);
+ return (TIME)0;
+ }
+
+ guess = atoi(val);
+
+ if (!parse_semi(cfile))
+ return (TIME)0;
+
+ return guess;
+ }
+
if (token != NUMBER) {
parse_warn (cfile, "numeric day of week expected.");
if (token != SEMI)
token = peek_token (&val, (unsigned *)0, cfile);
switch (token) {
+ case DB_TIME_FORMAT:
+ next_token(&val, NULL, cfile);
+
+ token = next_token(&val, NULL, cfile);
+ if (token == DEFAULT) {
+ db_time_format = DEFAULT_TIME_FORMAT;
+ } else if (token == LOCAL) {
+ db_time_format = LOCAL_TIME_FORMAT;
+ } else {
+ parse_warn(cfile, "Expecting 'local' or 'default'.");
+ if (token != SEMI)
+ skip_to_semi(cfile);
+ *lose = 1;
+ return 0;
+ }
+
+ token = next_token(&val, NULL, cfile);
+ if (token != SEMI) {
+ parse_warn(cfile, "Expecting a semicolon.");
+ *lose = 1;
+ return 0;
+ }
+
+ /* We're done here. */
+ return 1;
+
case IF:
next_token (&val, (unsigned *)0, cfile);
return parse_if_statement (result, cfile, lose);
return 0;
}
break;
-
+
/* Not really a statement, but we parse it here anyway
because it's appropriate for all DHCP agents with
parsers. */
#ifndef lint
static char copyright[] =
-"$Id: print.c,v 1.59 2006/05/11 16:31:29 dhankins Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n";
+"$Id: print.c,v 1.60 2006/06/06 16:35:18 dhankins Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n";
#endif /* not lint */
#include "dhcpd.h"
+int db_time_format = DEFAULT_TIME_FORMAT;
+
char *quotify_string (const char *s, const char *file, int line)
{
unsigned len = 0;
log_info ("%s", obuf);
}
#endif /* NSUPDATE */
+
+/* Format the given time as "A; # B", where A is the format
+ * used by the parser, and B is the local time, for humans.
+ */
+const char *
+print_time(TIME t)
+{
+ static char buf[sizeof("epoch 9223372036854775807; "
+ "# Wed Jun 30 21:49:08 2147483647")];
+ /* The string: "6 2147483647/12/31 23:59:60;"
+ * is smaller than the other, used to declare the buffer size, so
+ * we can use one buffer for both.
+ */
+
+ if (t == MAX_TIME)
+ return "never;";
+
+ if (t < 0)
+ return NULL;
+
+ /* For those lucky enough to have a 128-bit time_t, ensure that
+ * whatever (corrupt) value we're given doesn't exceed the static
+ * buffer.
+ */
+#if (MAX_TIME > 0x7fffffffffffffff)
+ if (t > 0x7fffffffffffffff)
+ return NULL;
+#endif
+
+ if (db_time_format == LOCAL_TIME_FORMAT) {
+ if (strftime(buf, sizeof(buf),
+ "epoch %s; # %a %b %d %H:%M:%S %Y",
+ localtime(&t)) == 0)
+ return NULL;
+ } else {
+ /* No bounds check for the year is necessary - in this case,
+ * strftime() will run out of space and assert an error.
+ */
+ if (strftime(buf, sizeof(buf), "%w %Y/%m/%d %H:%M:%S;",
+ gmtime(&t)) == 0)
+ return NULL;
+ }
+
+ return buf;
+}
struct dns_zone *, const char *, int));
/* print.c */
+#define DEFAULT_TIME_FORMAT 0
+#define LOCAL_TIME_FORMAT 1
+extern int db_time_format;
char *quotify_string (const char *, const char *, int);
char *quotify_buf (const unsigned char *, unsigned, const char *, int);
char *print_base64 (const unsigned char *, unsigned, const char *, int);
#if defined (NSUPDATE)
void print_dns_status (int, ns_updque *);
#endif
+const char *print_time(TIME);
/* socket.c */
#if defined (USE_SOCKET_SEND) || defined (USE_SOCKET_RECEIVE) \
WIDTH = 619,
LENGTH = 620,
HASH = 621,
- SIZE = 622
+ SIZE = 622,
+ EPOCH = 623,
+ DB_TIME_FORMAT = 624,
+ LOCAL = 625
};
#define is_identifier(x) ((x) >= FIRST_TOKEN && \
#ifndef lint
static char copyright[] =
-"$Id: db.c,v 1.72 2006/06/01 20:23:17 dhankins Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n";
+"$Id: db.c,v 1.73 2006/06/06 16:35:18 dhankins Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n";
#endif /* not lint */
#include "dhcpd.h"
int write_lease (lease)
struct lease *lease;
{
- struct tm *t;
- char tbuf [64];
int errors = 0;
int i;
struct binding *b;
char *s;
+ const char *tval;
/* If the lease file is corrupt, don't try to write any more leases
until we've written a good lease file. */
++errors;
}
- /* Note: the following is not a Y2K bug - it's a Y1.9K bug. Until
- somebody invents a time machine, I think we can safely disregard
- it. */
- if (lease -> starts) {
- if (lease -> starts != MAX_TIME) {
- t = gmtime (&lease -> starts);
- /* %Audit% Cannot exceed 59 bytes. %2004.06.17,Safe% */
- sprintf (tbuf, "%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);
- } else
- strcpy (tbuf, "never;");
- errno = 0;
- fprintf (db_file, "\n starts %s", tbuf);
- if (errno) {
- ++errors;
- }
- }
+ if (lease->starts &&
+ ((tval = print_time(lease->starts)) == NULL ||
+ fprintf(db_file, "\n starts %s", tval) < 0))
+ ++errors;
- if (lease -> ends) {
- if (lease -> ends != MAX_TIME) {
- t = gmtime (&lease -> ends);
- /* %Audit% Cannot exceed 59 bytes. %2004.06.17,Safe% */
- sprintf (tbuf, "%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);
- } else
- strcpy (tbuf, "never;");
- errno = 0;
- fprintf (db_file, "\n ends %s", tbuf);
- if (errno) {
- ++errors;
- }
- }
+ if (lease->ends &&
+ ((tval = print_time(lease->ends)) == NULL ||
+ fprintf(db_file, "\n ends %s", tval) < 0))
+ ++errors;
- 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);
- if (errno) {
- ++errors;
- }
- }
- if (lease -> tsfp) {
- t = gmtime (&lease -> tsfp);
- errno = 0;
- 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);
- if (errno) {
- ++errors;
- }
- }
- if (lease->atsfp) {
- t = gmtime(&lease->atsfp);
- if (fprintf(db_file,
- "\n atsfp %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) <= 0)
- ++errors;
- }
- if (lease -> cltt) {
- t = gmtime (&lease -> cltt);
- errno = 0;
- 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);
- if (errno) {
- ++errors;
- }
- }
+ if (lease->tstp &&
+ ((tval = print_time(lease->tstp)) == NULL ||
+ fprintf(db_file, "\n tstp %s", tval) < 0))
+ ++errors;
+
+ if (lease->tsfp &&
+ ((tval = print_time(lease->tsfp)) == NULL ||
+ fprintf(db_file, "\n tsfp %s", tval) < 0))
+ ++errors;
+
+ if (lease->atsfp &&
+ ((tval = print_time(lease->atsfp)) == NULL ||
+ fprintf(db_file, "\n atsfp %s", tval) < 0))
+ ++errors;
+
+ if (lease->cltt &&
+ ((tval = print_time(lease->cltt)) == NULL ||
+ fprintf(db_file, "\n cltt %s", tval) < 0))
+ ++errors;
fprintf (db_file, "\n binding state %s;",
((lease -> binding_state > 0 &&
{
struct tm *t;
int errors = 0;
+ const char *tval;
if (lease_file_is_corrupt)
if (!new_lease_file ())
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);
- if (errno)
+ tval = print_time(state->me.stos);
+ if (tval == NULL ||
+ fprintf(db_file, "\n my state %s at %s",
+ (state->me.state == startup) ?
+ dhcp_failover_state_name_print(state->saved_state) :
+ dhcp_failover_state_name_print(state->me.state),
+ tval) < 0)
++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);
- if (errno)
+ tval = print_time(state->partner.stos);
+ if (tval == NULL ||
+ fprintf(db_file, "\n partner state %s at %s",
+ dhcp_failover_state_name_print(state->partner.state),
+ tval) < 0)
++errors;
if (state -> i_am == secondary) {
fclose(db_file);
db_file = new_db_file;
- /* Write an introduction so people don't complain about time
- being off. */
errno = 0;
- fprintf (db_file, "# All times in this file are in UTC (GMT), not %s",
- "your local timezone. This is\n");
- if (errno != 0)
- goto fail;
- fprintf (db_file, "# not a bug, so please don't ask about it. %s",
- "There is no portable way to\n");
- if (errno != 0)
- goto fail;
- fprintf (db_file, "# store leases in the local timezone, so please %s",
- "don't request this as a\n");
- if (errno != 0)
- goto fail;
- fprintf (db_file, "# feature. If this is inconvenient or %s",
- "confusing to you, we sincerely\n");
- if (errno != 0)
- goto fail;
- fprintf (db_file, "# apologize. Seriously, though - don't ask.\n");
- if (errno != 0)
- goto fail;
fprintf (db_file, "# The format of this file is documented in the %s",
"dhcpd.leases(5) manual page.\n");
if (errno != 0)