3 Persistent database management routines for DHCPD... */
6 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
7 * Copyright (c) 1995-2003 by Internet Software Consortium
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
13 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 * Internet Systems Consortium, Inc.
23 * Redwood City, CA 94063
27 * This software has been written for Internet Systems Consortium
28 * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
29 * To learn more about Internet Systems Consortium, see
30 * ``http://www.isc.org/''. To learn more about Vixie Enterprises,
31 * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
32 * ``http://www.nominum.com''.
36 static char copyright
[] =
37 "$Id$ Copyright (c) 2004 Internet Systems Consortium. All rights reserved.\n";
46 static int counting
= 0;
49 int lease_file_is_corrupt
= 0;
51 /* Write the specified lease to the current lease database file. */
53 int write_lease (lease
)
63 /* If the lease file is corrupt, don't try to write any more leases
64 until we've written a good lease file. */
65 if (lease_file_is_corrupt
)
66 if (!new_lease_file ())
72 fprintf (db_file
, "lease %s {", piaddr (lease
-> ip_addr
));
77 /* Note: the following is not a Y2K bug - it's a Y1.9K bug. Until
78 somebody invents a time machine, I think we can safely disregard
80 if (lease
-> starts
) {
81 if (lease
-> starts
!= MAX_TIME
) {
82 t
= gmtime (&lease
-> starts
);
83 /* %Audit% Cannot exceed 59 bytes. %2004.06.17,Safe% */
84 sprintf (tbuf
, "%d %d/%02d/%02d %02d:%02d:%02d;",
85 t
-> tm_wday
, t
-> tm_year
+ 1900,
86 t
-> tm_mon
+ 1, t
-> tm_mday
,
87 t
-> tm_hour
, t
-> tm_min
, t
-> tm_sec
);
89 strcpy (tbuf
, "never;");
91 fprintf (db_file
, "\n starts %s", tbuf
);
98 if (lease
-> ends
!= MAX_TIME
) {
99 t
= gmtime (&lease
-> ends
);
100 /* %Audit% Cannot exceed 59 bytes. %2004.06.17,Safe% */
101 sprintf (tbuf
, "%d %d/%02d/%02d %02d:%02d:%02d;",
102 t
-> tm_wday
, t
-> tm_year
+ 1900,
103 t
-> tm_mon
+ 1, t
-> tm_mday
,
104 t
-> tm_hour
, t
-> tm_min
, t
-> tm_sec
);
106 strcpy (tbuf
, "never;");
108 fprintf (db_file
, "\n ends %s", tbuf
);
115 t
= gmtime (&lease
-> tstp
);
117 fprintf (db_file
, "\n tstp %d %d/%02d/%02d %02d:%02d:%02d;",
118 t
-> tm_wday
, t
-> tm_year
+ 1900,
119 t
-> tm_mon
+ 1, t
-> tm_mday
,
120 t
-> tm_hour
, t
-> tm_min
, t
-> tm_sec
);
126 t
= gmtime (&lease
-> tsfp
);
128 fprintf (db_file
, "\n tsfp %d %d/%02d/%02d %02d:%02d:%02d;",
129 t
-> tm_wday
, t
-> tm_year
+ 1900,
130 t
-> tm_mon
+ 1, t
-> tm_mday
,
131 t
-> tm_hour
, t
-> tm_min
, t
-> tm_sec
);
137 t
= gmtime (&lease
-> cltt
);
139 fprintf (db_file
, "\n cltt %d %d/%02d/%02d %02d:%02d:%02d;",
140 t
-> tm_wday
, t
-> tm_year
+ 1900,
141 t
-> tm_mon
+ 1, t
-> tm_mday
,
142 t
-> tm_hour
, t
-> tm_min
, t
-> tm_sec
);
148 if (lease
-> binding_state
== FTS_ACTIVE
&&
149 (lease
-> flags
& BOOTP_LEASE
)) {
150 fprintf (db_file
, "\n binding state bootp;\n");
152 fprintf (db_file
, "\n binding state %s;",
153 ((lease
-> binding_state
> 0 &&
154 lease
-> binding_state
<= FTS_LAST
)
155 ? binding_state_names
[lease
-> binding_state
- 1]
159 if (lease
-> binding_state
!= lease
-> next_binding_state
) {
160 if (lease
-> next_binding_state
== FTS_ACTIVE
&&
161 (lease
-> flags
& BOOTP_LEASE
))
162 fprintf (db_file
, "\n next binding state bootp;\n");
164 fprintf (db_file
, "\n next binding state %s;",
165 ((lease
-> next_binding_state
> 0 &&
166 lease
-> next_binding_state
<= FTS_LAST
)
167 ? (binding_state_names
168 [lease
-> next_binding_state
- 1])
172 /* If this lease is billed to a class and is still valid,
174 if (lease
-> billing_class
&& lease
-> ends
> cur_time
) {
175 if (!write_billing_class (lease
-> billing_class
)) {
176 log_error ("unable to write class %s",
177 lease
-> billing_class
-> name
);
182 if (lease
-> hardware_addr
.hlen
) {
184 fprintf (db_file
, "\n hardware %s %s;",
185 hardware_types
[lease
-> hardware_addr
.hbuf
[0]],
186 print_hw_addr (lease
-> hardware_addr
.hbuf
[0],
187 lease
-> hardware_addr
.hlen
- 1,
188 &lease
-> hardware_addr
.hbuf
[1]));
193 if (lease
-> uid_len
) {
195 s
= quotify_buf (lease
-> uid
, lease
-> uid_len
, MDL
);
197 fprintf (db_file
, "\n uid \"%s\";", s
);
204 if (lease
-> scope
) {
205 for (b
= lease
-> scope
-> bindings
; b
; b
= b
-> next
) {
208 if (b
-> value
-> type
== binding_data
) {
209 if (b
-> value
-> value
.data
.data
) {
210 s
= quotify_buf (b
-> value
-> value
.data
.data
,
211 b
-> value
-> value
.data
.len
, MDL
);
214 fprintf (db_file
, "\n set %s = \"%s\";",
222 } else if (b
-> value
-> type
== binding_numeric
) {
224 fprintf (db_file
, "\n set %s = %%%ld;",
225 b
-> name
, b
-> value
-> value
.intval
);
228 } else if (b
-> value
-> type
== binding_boolean
) {
230 fprintf (db_file
, "\n set %s = %s;",
232 b
-> value
-> value
.intval
? "true" : "false");
235 } else if (b
-> value
-> type
== binding_dns
) {
236 log_error ("%s: persistent dns values not supported.",
238 } else if (b
-> value
-> type
== binding_function
) {
239 log_error ("%s: persistent functions not supported.",
242 log_error ("%s: unknown binding type %d",
243 b
-> name
, b
-> value
-> type
);
247 if (lease
-> agent_options
) {
248 struct option_cache
*oc
;
249 struct data_string ds
;
252 memset (&ds
, 0, sizeof ds
);
253 for (p
= lease
-> agent_options
-> first
; p
; p
= p
-> cdr
) {
254 oc
= (struct option_cache
*)p
-> car
;
255 if (oc
-> data
.len
) {
257 fprintf (db_file
, "\n option agent.%s %s;",
258 oc
-> option
-> name
,
259 pretty_print_option (oc
-> option
, oc
-> data
.data
,
260 oc
-> data
.len
, 1, 1));
266 if (lease
-> client_hostname
&&
267 db_printable (lease
-> client_hostname
)) {
268 s
= quotify_string (lease
-> client_hostname
, MDL
);
271 fprintf (db_file
, "\n client-hostname \"%s\";", s
);
278 if (lease
-> on_expiry
) {
280 fprintf (db_file
, "\n on expiry%s {",
281 lease
-> on_expiry
== lease
-> on_release
282 ? " or release" : "");
285 write_statements (db_file
, lease
-> on_expiry
, 4);
287 fprintf (db_file
, "\n }");
289 if (lease
-> on_release
&& lease
-> on_release
!= lease
-> on_expiry
) {
291 fprintf (db_file
, "\n on release {");
294 write_statements (db_file
, lease
-> on_release
, 4);
296 fprintf (db_file
, "\n }");
299 fputs ("\n}\n", db_file
);
304 log_info ("write_lease: unable to write lease %s",
305 piaddr (lease
-> ip_addr
));
307 lease_file_is_corrupt
= 1;
311 int write_host (host
)
312 struct host_decl
*host
;
316 struct data_string ip_addrs
;
318 /* If the lease file is corrupt, don't try to write any more leases
319 until we've written a good lease file. */
320 if (lease_file_is_corrupt
)
321 if (!new_lease_file ())
324 if (!db_printable (host
-> name
))
331 fprintf (db_file
, "host %s {", host
-> name
);
336 if (host
-> flags
& HOST_DECL_DYNAMIC
) {
338 fprintf (db_file
, "\n dynamic;");
343 if (host
-> flags
& HOST_DECL_DELETED
) {
345 fprintf (db_file
, "\n deleted;");
349 if (host
-> interface
.hlen
) {
351 fprintf (db_file
, "\n hardware %s %s;",
352 hardware_types
[host
-> interface
.hbuf
[0]],
353 print_hw_addr (host
-> interface
.hbuf
[0],
354 host
-> interface
.hlen
- 1,
355 &host
-> interface
.hbuf
[1]));
360 if (host
-> client_identifier
.len
) {
363 if (db_printable_len (host
-> client_identifier
.data
,
364 host
-> client_identifier
.len
)) {
365 fprintf (db_file
, "\n uid \"%.*s\";",
366 (int)host
-> client_identifier
.len
,
367 host
-> client_identifier
.data
);
371 host
-> client_identifier
.data
[0]);
376 i
< host
-> client_identifier
.len
; i
++) {
378 fprintf (db_file
, ":%2.2x",
380 client_identifier
.data
[i
]);
389 memset (&ip_addrs
, 0, sizeof ip_addrs
);
390 if (host
-> fixed_addr
&&
391 evaluate_option_cache (&ip_addrs
, (struct packet
*)0,
393 (struct client_state
*)0,
394 (struct option_state
*)0,
395 (struct option_state
*)0,
397 host
-> fixed_addr
, MDL
)) {
400 fprintf (db_file
, "\n fixed-address ");
404 for (i
= 0; i
< ip_addrs
.len
- 3; i
+= 4) {
406 fprintf (db_file
, "%u.%u.%u.%u%s",
407 ip_addrs
.data
[i
] & 0xff,
408 ip_addrs
.data
[i
+ 1] & 0xff,
409 ip_addrs
.data
[i
+ 2] & 0xff,
410 ip_addrs
.data
[i
+ 3] & 0xff,
411 i
+ 7 < ip_addrs
.len
? "," : "");
417 fputc (';', db_file
);
423 if (host
-> named_group
) {
425 fprintf (db_file
, "\n group \"%s\";",
426 host
-> named_group
-> name
);
433 (!host
-> named_group
||
434 host
-> group
!= host
-> named_group
-> group
) &&
435 host
-> group
!= root_group
) {
437 write_statements (db_file
,
438 host
-> group
-> statements
, 8);
446 fputs ("\n}\n", db_file
);
451 log_info ("write_host: unable to write host %s",
453 lease_file_is_corrupt
= 1;
458 int write_group (group
)
459 struct group_object
*group
;
464 /* If the lease file is corrupt, don't try to write any more leases
465 until we've written a good lease file. */
466 if (lease_file_is_corrupt
)
467 if (!new_lease_file ())
470 if (!db_printable (group
-> name
))
477 fprintf (db_file
, "group %s {", group
-> name
);
482 if (group
-> flags
& GROUP_OBJECT_DYNAMIC
) {
484 fprintf (db_file
, "\n dynamic;");
489 if (group
-> flags
& GROUP_OBJECT_STATIC
) {
491 fprintf (db_file
, "\n static;");
496 if (group
-> flags
& GROUP_OBJECT_DELETED
) {
498 fprintf (db_file
, "\n deleted;");
502 if (group
-> group
) {
504 write_statements (db_file
,
505 group
-> group
-> statements
, 8);
513 fputs ("\n}\n", db_file
);
518 log_info ("write_group: unable to write group %s",
520 lease_file_is_corrupt
= 1;
525 #if defined (FAILOVER_PROTOCOL)
526 int write_failover_state (dhcp_failover_state_t
*state
)
531 if (lease_file_is_corrupt
)
532 if (!new_lease_file ())
536 fprintf (db_file
, "\nfailover peer \"%s\" state {", state
-> name
);
540 t
= gmtime (&state
-> me
.stos
);
542 fprintf (db_file
, "\n my state %s at %d %d/%02d/%02d %02d:%02d:%02d;",
543 /* Never record our state as "startup"! */
544 (state
-> me
.state
== startup
545 ? dhcp_failover_state_name_print (state
-> saved_state
)
546 : dhcp_failover_state_name_print (state
-> me
.state
)),
547 t
-> tm_wday
, t
-> tm_year
+ 1900,
548 t
-> tm_mon
+ 1, t
-> tm_mday
,
549 t
-> tm_hour
, t
-> tm_min
, t
-> tm_sec
);
553 t
= gmtime (&state
-> partner
.stos
);
556 "\n partner state %s at %d %d/%02d/%02d %02d:%02d:%02d;",
557 dhcp_failover_state_name_print (state
-> partner
.state
),
558 t
-> tm_wday
, t
-> tm_year
+ 1900,
559 t
-> tm_mon
+ 1, t
-> tm_mday
,
560 t
-> tm_hour
, t
-> tm_min
, t
-> tm_sec
);
564 if (state
-> i_am
== secondary
) {
566 fprintf (db_file
, "\n mclt %ld;",
567 (unsigned long)state
-> mclt
);
571 fprintf (db_file
, "\n}\n");
576 log_info ("write_failover_state: unable to write state %s",
578 lease_file_is_corrupt
= 1;
590 for (i
= 0; s
[i
]; i
++)
591 if (!isascii (s
[i
]) || !isprint (s
[i
])
592 || s
[i
] == '"' || s
[i
] == '\\')
597 int db_printable_len (s
, len
)
598 const unsigned char *s
;
602 for (i
= 0; i
< len
; i
++)
603 if (!isascii (s
[i
]) || !isprint (s
[i
]) ||
604 s
[i
] == '"' || s
[i
] == '\\')
609 void write_named_billing_class (const char *name
, unsigned len
,
612 /* XXX billing classes that are modified by OMAPI need
613 XXX to be detected and written out here. */
616 void write_billing_classes ()
618 struct collection
*lp
;
620 struct hash_bucket
*bp
;
623 for (lp
= collections
; lp
; lp
= lp
-> next
) {
624 for (cp
= lp
-> classes
; cp
; cp
= cp
-> nic
) {
625 if (cp
-> spawning
&& cp
-> hash
) {
626 class_hash_foreach (cp
-> hash
, write_named_billing_class
);
632 /* Write a spawned class to the database file. */
634 int write_billing_class (class)
640 if (lease_file_is_corrupt
)
641 if (!new_lease_file ())
644 if (!class -> superclass
) {
646 fprintf (db_file
, "\n billing class \"%s\";", class -> name
);
651 fprintf (db_file
, "\n billing subclass \"%s\"",
652 class -> superclass
-> name
);
656 for (i
= 0; i
< class -> hash_string
.len
; i
++)
657 if (!isascii (class -> hash_string
.data
[i
]) ||
658 !isprint (class -> hash_string
.data
[i
]))
660 if (i
== class -> hash_string
.len
) {
662 fprintf (db_file
, " \"%.*s\";",
663 (int)class -> hash_string
.len
,
664 class -> hash_string
.data
);
669 fprintf (db_file
, " %2.2x", class -> hash_string
.data
[0]);
672 for (i
= 1; i
< class -> hash_string
.len
; i
++) {
674 fprintf (db_file
, ":%2.2x",
675 class -> hash_string
.data
[i
]);
680 fprintf (db_file
, ";");
685 class -> dirty
= !errors
;
687 lease_file_is_corrupt
= 1;
691 /* Commit leases after a timeout. */
692 void commit_leases_timeout (void *foo
)
697 /* Commit any leases that have been written out... */
701 /* Commit any outstanding writes to the lease database file.
702 We need to do this even if we're rewriting the file below,
703 just in case the rewrite fails. */
704 if (fflush (db_file
) == EOF
) {
705 log_info ("commit_leases: unable to commit: %m");
708 #ifndef FSYNC_MISSING
709 if (fsync (fileno (db_file
)) < 0) {
710 log_info ("commit_leases: unable to commit: %m");
715 /* If we haven't rewritten the lease database in over an
716 hour, rewrite it now. (The length of time should probably
718 if (count
&& cur_time
- write_time
> 3600) {
720 write_time
= cur_time
;
726 void db_startup (testp
)
731 #if defined (TRACING)
732 if (!trace_playback ()) {
734 /* Read in the existing lease file... */
735 status
= read_conf_file (path_dhcpd_db
,
736 (struct group
*)0, 0, 1);
737 /* XXX ignore status? */
738 #if defined (TRACING)
742 #if defined (TRACING)
743 /* If we're playing back, there is no lease file, so we can't
744 append it, so we create one immediately (maybe this isn't
745 the best solution... */
746 if (trace_playback ()) {
751 db_file
= fopen (path_dhcpd_db
, "a");
753 log_fatal ("Can't open %s for append.", path_dhcpd_db
);
755 #if defined (TRACING)
756 if (trace_playback ())
757 write_time
= cur_time
;
760 GET_TIME (&write_time
);
765 int new_lease_file ()
768 char backfname
[512];
772 /* If we already have an open database, close it. */
778 /* Make a temporary lease file... */
781 /* %Audit% Truncated filename causes panic. %2004.06.17,Safe%
782 * This should never happen since the path is a configuration
783 * variable from build-time or command-line. But if it should,
784 * either by malice or ignorance, we panic, since the potential
787 if (snprintf (newfname
, sizeof newfname
, "%s.%d",
788 path_dhcpd_db
, (int)t
) >= sizeof newfname
)
789 log_fatal("new_lease_file: lease file path too long");
791 db_fd
= open (newfname
, O_WRONLY
| O_TRUNC
| O_CREAT
, 0664);
793 log_error ("Can't create new lease file: %m");
796 if ((db_file
= fdopen (db_fd
, "w")) == NULL
) {
797 log_error ("Can't fdopen new lease file!");
801 /* Write an introduction so people don't complain about time
804 fprintf (db_file
, "# All times in this file are in UTC (GMT), not %s",
805 "your local timezone. This is\n");
808 fprintf (db_file
, "# not a bug, so please don't ask about it. %s",
809 "There is no portable way to\n");
812 fprintf (db_file
, "# store leases in the local timezone, so please %s",
813 "don't request this as a\n");
816 fprintf (db_file
, "# feature. If this is inconvenient or %s",
817 "confusing to you, we sincerely\n");
820 fprintf (db_file
, "# apologize. Seriously, though - don't ask.\n");
823 fprintf (db_file
, "# The format of this file is documented in the %s",
824 "dhcpd.leases(5) manual page.\n");
827 fprintf (db_file
, "# This lease file was written by isc-dhcp-%s\n\n",
832 /* Write out all the leases that we know of... */
834 if (!write_leases ())
837 #if defined (TRACING)
838 if (!trace_playback ()) {
840 /* %Audit% Truncated filename causes panic. %2004.06.17,Safe%
841 * This should never happen since the path is a configuration
842 * variable from build-time or command-line. But if it should,
843 * either by malice or ignorance, we panic, since the potential
844 * for havoc is too high.
846 if (snprintf (backfname
, sizeof backfname
, "%s~", path_dhcpd_db
)
848 log_fatal("new_lease_file: backup lease file path too long");
850 /* Get the old database out of the way... */
851 if (unlink (backfname
) < 0 && errno
!= ENOENT
) {
852 log_error ("Can't remove old lease database backup %s: %m",
856 if (rename (path_dhcpd_db
, backfname
) < 0) {
857 log_error ("Can't backup lease database %s to %s: %m",
858 path_dhcpd_db
, backfname
);
861 #if defined (TRACING)
865 /* Move in the new file... */
866 if (rename (newfname
, path_dhcpd_db
) < 0) {
867 log_error ("Can't install new lease database %s to %s: %m",
868 newfname
, path_dhcpd_db
);
873 lease_file_is_corrupt
= 0;
878 lease_file_is_corrupt
= 1;
882 int group_writer (struct group_object
*group
)
884 if (!write_group (group
))
886 if (!commit_leases ())