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: db.c,v 1.6 2005/08/11 17:13:30 drochner Exp $ 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
)
62 /* If the lease file is corrupt, don't try to write any more leases
63 until we've written a good lease file. */
64 if (lease_file_is_corrupt
)
65 if (!new_lease_file ())
71 fprintf (db_file
, "lease %s {", piaddr (lease
-> ip_addr
));
76 /* Note: the following is not a Y2K bug - it's a Y1.9K bug. Until
77 somebody invents a time machine, I think we can safely disregard
79 if (lease
-> starts
) {
80 if (lease
-> starts
!= MAX_TIME
) {
81 t
= gmtime (&lease
-> starts
);
82 /* %Audit% Cannot exceed 59 bytes. %2004.06.17,Safe% */
83 sprintf (tbuf
, "%d %d/%02d/%02d %02d:%02d:%02d;",
84 t
-> tm_wday
, t
-> tm_year
+ 1900,
85 t
-> tm_mon
+ 1, t
-> tm_mday
,
86 t
-> tm_hour
, t
-> tm_min
, t
-> tm_sec
);
88 strcpy (tbuf
, "never;");
90 fprintf (db_file
, "\n starts %s", tbuf
);
97 if (lease
-> ends
!= MAX_TIME
) {
98 t
= gmtime (&lease
-> ends
);
99 /* %Audit% Cannot exceed 59 bytes. %2004.06.17,Safe% */
100 sprintf (tbuf
, "%d %d/%02d/%02d %02d:%02d:%02d;",
101 t
-> tm_wday
, t
-> tm_year
+ 1900,
102 t
-> tm_mon
+ 1, t
-> tm_mday
,
103 t
-> tm_hour
, t
-> tm_min
, t
-> tm_sec
);
105 strcpy (tbuf
, "never;");
107 fprintf (db_file
, "\n ends %s", tbuf
);
114 t
= gmtime (&lease
-> tstp
);
116 fprintf (db_file
, "\n tstp %d %d/%02d/%02d %02d:%02d:%02d;",
117 t
-> tm_wday
, t
-> tm_year
+ 1900,
118 t
-> tm_mon
+ 1, t
-> tm_mday
,
119 t
-> tm_hour
, t
-> tm_min
, t
-> tm_sec
);
125 t
= gmtime (&lease
-> tsfp
);
127 fprintf (db_file
, "\n tsfp %d %d/%02d/%02d %02d:%02d:%02d;",
128 t
-> tm_wday
, t
-> tm_year
+ 1900,
129 t
-> tm_mon
+ 1, t
-> tm_mday
,
130 t
-> tm_hour
, t
-> tm_min
, t
-> tm_sec
);
136 t
= gmtime (&lease
-> cltt
);
138 fprintf (db_file
, "\n cltt %d %d/%02d/%02d %02d:%02d:%02d;",
139 t
-> tm_wday
, t
-> tm_year
+ 1900,
140 t
-> tm_mon
+ 1, t
-> tm_mday
,
141 t
-> tm_hour
, t
-> tm_min
, t
-> tm_sec
);
147 if (lease
-> binding_state
== FTS_ACTIVE
&&
148 (lease
-> flags
& BOOTP_LEASE
)) {
149 fprintf (db_file
, "\n binding state bootp;\n");
151 fprintf (db_file
, "\n binding state %s;",
152 ((lease
-> binding_state
> 0 &&
153 lease
-> binding_state
<= FTS_LAST
)
154 ? binding_state_names
[lease
-> binding_state
- 1]
158 if (lease
-> binding_state
!= lease
-> next_binding_state
) {
159 if (lease
-> next_binding_state
== FTS_ACTIVE
&&
160 (lease
-> flags
& BOOTP_LEASE
))
161 fprintf (db_file
, "\n next binding state bootp;\n");
163 fprintf (db_file
, "\n next binding state %s;",
164 ((lease
-> next_binding_state
> 0 &&
165 lease
-> next_binding_state
<= FTS_LAST
)
166 ? (binding_state_names
167 [lease
-> next_binding_state
- 1])
171 /* If this lease is billed to a class and is still valid,
173 if (lease
-> billing_class
&& lease
-> ends
> cur_time
) {
174 if (!write_billing_class (lease
-> billing_class
)) {
175 log_error ("unable to write class %s",
176 lease
-> billing_class
-> name
);
181 if (lease
-> hardware_addr
.hlen
) {
183 fprintf (db_file
, "\n hardware %s %s;",
184 hardware_types
[lease
-> hardware_addr
.hbuf
[0]],
185 print_hw_addr (lease
-> hardware_addr
.hbuf
[0],
186 lease
-> hardware_addr
.hlen
- 1,
187 &lease
-> hardware_addr
.hbuf
[1]));
192 if (lease
-> uid_len
) {
193 s
= quotify_buf (lease
-> uid
, lease
-> uid_len
, MDL
);
195 fprintf (db_file
, "\n uid \"%s\";", s
);
202 if (lease
-> scope
) {
203 for (b
= lease
-> scope
-> bindings
; b
; b
= b
-> next
) {
206 if (b
-> value
-> type
== binding_data
) {
207 if (b
-> value
-> value
.data
.data
) {
208 s
= quotify_buf (b
-> value
-> value
.data
.data
,
209 b
-> value
-> value
.data
.len
, MDL
);
212 fprintf (db_file
, "\n set %s = \"%s\";",
220 } else if (b
-> value
-> type
== binding_numeric
) {
222 fprintf (db_file
, "\n set %s = %%%ld;",
223 b
-> name
, b
-> value
-> value
.intval
);
226 } else if (b
-> value
-> type
== binding_boolean
) {
228 fprintf (db_file
, "\n set %s = %s;",
230 b
-> value
-> value
.intval
? "true" : "false");
233 } else if (b
-> value
-> type
== binding_dns
) {
234 log_error ("%s: persistent dns values not supported.",
236 } else if (b
-> value
-> type
== binding_function
) {
237 log_error ("%s: persistent functions not supported.",
240 log_error ("%s: unknown binding type %d",
241 b
-> name
, b
-> value
-> type
);
245 if (lease
-> agent_options
) {
246 struct option_cache
*oc
;
247 struct data_string ds
;
250 memset (&ds
, 0, sizeof ds
);
251 for (p
= lease
-> agent_options
-> first
; p
; p
= p
-> cdr
) {
252 oc
= (struct option_cache
*)p
-> car
;
253 if (oc
-> data
.len
) {
255 fprintf (db_file
, "\n option agent.%s %s;",
256 oc
-> option
-> name
,
257 pretty_print_option (oc
-> option
, oc
-> data
.data
,
258 oc
-> data
.len
, 1, 1));
264 if (lease
-> client_hostname
&&
265 db_printable (lease
-> client_hostname
)) {
266 s
= quotify_string (lease
-> client_hostname
, MDL
);
269 fprintf (db_file
, "\n client-hostname \"%s\";", s
);
276 if (lease
-> on_expiry
) {
278 fprintf (db_file
, "\n on expiry%s {",
279 lease
-> on_expiry
== lease
-> on_release
280 ? " or release" : "");
283 write_statements (db_file
, lease
-> on_expiry
, 4);
285 fprintf (db_file
, "\n }");
287 if (lease
-> on_release
&& lease
-> on_release
!= lease
-> on_expiry
) {
289 fprintf (db_file
, "\n on release {");
292 write_statements (db_file
, lease
-> on_release
, 4);
294 fprintf (db_file
, "\n }");
297 fputs ("\n}\n", db_file
);
302 log_info ("write_lease: unable to write lease %s",
303 piaddr (lease
-> ip_addr
));
305 lease_file_is_corrupt
= 1;
309 int write_host (host
)
310 struct host_decl
*host
;
314 struct data_string ip_addrs
;
316 /* If the lease file is corrupt, don't try to write any more leases
317 until we've written a good lease file. */
318 if (lease_file_is_corrupt
)
319 if (!new_lease_file ())
322 if (!db_printable (host
-> name
))
329 fprintf (db_file
, "host %s {", host
-> name
);
334 if (host
-> flags
& HOST_DECL_DYNAMIC
) {
336 fprintf (db_file
, "\n dynamic;");
341 if (host
-> flags
& HOST_DECL_DELETED
) {
343 fprintf (db_file
, "\n deleted;");
347 if (host
-> interface
.hlen
) {
349 fprintf (db_file
, "\n hardware %s %s;",
350 hardware_types
[host
-> interface
.hbuf
[0]],
351 print_hw_addr (host
-> interface
.hbuf
[0],
352 host
-> interface
.hlen
- 1,
353 &host
-> interface
.hbuf
[1]));
358 if (host
-> client_identifier
.len
) {
361 if (db_printable_len (host
-> client_identifier
.data
,
362 host
-> client_identifier
.len
)) {
363 fprintf (db_file
, "\n uid \"%.*s\";",
364 (int)host
-> client_identifier
.len
,
365 host
-> client_identifier
.data
);
369 host
-> client_identifier
.data
[0]);
374 i
< host
-> client_identifier
.len
; i
++) {
376 fprintf (db_file
, ":%2.2x",
378 client_identifier
.data
[i
]);
387 memset (&ip_addrs
, 0, sizeof ip_addrs
);
388 if (host
-> fixed_addr
&&
389 evaluate_option_cache (&ip_addrs
, (struct packet
*)0,
391 (struct client_state
*)0,
392 (struct option_state
*)0,
393 (struct option_state
*)0,
395 host
-> fixed_addr
, MDL
)) {
398 fprintf (db_file
, "\n fixed-address ");
402 for (i
= 0; i
< ip_addrs
.len
- 3; i
+= 4) {
404 fprintf (db_file
, "%u.%u.%u.%u%s",
405 ip_addrs
.data
[i
] & 0xff,
406 ip_addrs
.data
[i
+ 1] & 0xff,
407 ip_addrs
.data
[i
+ 2] & 0xff,
408 ip_addrs
.data
[i
+ 3] & 0xff,
409 i
+ 7 < ip_addrs
.len
? "," : "");
415 fputc (';', db_file
);
421 if (host
-> named_group
) {
423 fprintf (db_file
, "\n group \"%s\";",
424 host
-> named_group
-> name
);
431 (!host
-> named_group
||
432 host
-> group
!= host
-> named_group
-> group
) &&
433 host
-> group
!= root_group
) {
435 write_statements (db_file
,
436 host
-> group
-> statements
, 8);
444 fputs ("\n}\n", db_file
);
449 log_info ("write_host: unable to write host %s",
451 lease_file_is_corrupt
= 1;
456 int write_group (group
)
457 struct group_object
*group
;
461 /* If the lease file is corrupt, don't try to write any more leases
462 until we've written a good lease file. */
463 if (lease_file_is_corrupt
)
464 if (!new_lease_file ())
467 if (!db_printable (group
-> name
))
474 fprintf (db_file
, "group %s {", group
-> name
);
479 if (group
-> flags
& GROUP_OBJECT_DYNAMIC
) {
481 fprintf (db_file
, "\n dynamic;");
486 if (group
-> flags
& GROUP_OBJECT_STATIC
) {
488 fprintf (db_file
, "\n static;");
493 if (group
-> flags
& GROUP_OBJECT_DELETED
) {
495 fprintf (db_file
, "\n deleted;");
499 if (group
-> group
) {
501 write_statements (db_file
,
502 group
-> group
-> statements
, 8);
510 fputs ("\n}\n", db_file
);
515 log_info ("write_group: unable to write group %s",
517 lease_file_is_corrupt
= 1;
522 #if defined (FAILOVER_PROTOCOL)
523 int write_failover_state (dhcp_failover_state_t
*state
)
528 if (lease_file_is_corrupt
)
529 if (!new_lease_file ())
533 fprintf (db_file
, "\nfailover peer \"%s\" state {", state
-> name
);
537 t
= gmtime (&state
-> me
.stos
);
539 fprintf (db_file
, "\n my state %s at %d %d/%02d/%02d %02d:%02d:%02d;",
540 /* Never record our state as "startup"! */
541 (state
-> me
.state
== startup
542 ? dhcp_failover_state_name_print (state
-> saved_state
)
543 : dhcp_failover_state_name_print (state
-> me
.state
)),
544 t
-> tm_wday
, t
-> tm_year
+ 1900,
545 t
-> tm_mon
+ 1, t
-> tm_mday
,
546 t
-> tm_hour
, t
-> tm_min
, t
-> tm_sec
);
550 t
= gmtime (&state
-> partner
.stos
);
553 "\n partner state %s at %d %d/%02d/%02d %02d:%02d:%02d;",
554 dhcp_failover_state_name_print (state
-> partner
.state
),
555 t
-> tm_wday
, t
-> tm_year
+ 1900,
556 t
-> tm_mon
+ 1, t
-> tm_mday
,
557 t
-> tm_hour
, t
-> tm_min
, t
-> tm_sec
);
561 if (state
-> i_am
== secondary
) {
563 fprintf (db_file
, "\n mclt %ld;",
564 (unsigned long)state
-> mclt
);
568 fprintf (db_file
, "\n}\n");
573 log_info ("write_failover_state: unable to write state %s",
575 lease_file_is_corrupt
= 1;
587 for (i
= 0; s
[i
]; i
++)
588 if (!isascii (s
[i
]) || !isprint ((unsigned char)s
[i
])
589 || s
[i
] == '"' || s
[i
] == '\\')
594 int db_printable_len (s
, len
)
595 const unsigned char *s
;
599 for (i
= 0; i
< len
; i
++)
600 if (!isascii (s
[i
]) || !isprint (s
[i
]) ||
601 s
[i
] == '"' || s
[i
] == '\\')
606 void write_named_billing_class (const char *name
, unsigned len
,
609 /* XXX billing classes that are modified by OMAPI need
610 XXX to be detected and written out here. */
613 void write_billing_classes ()
615 struct collection
*lp
;
618 for (lp
= collections
; lp
; lp
= lp
-> next
) {
619 for (cp
= lp
-> classes
; cp
; cp
= cp
-> nic
) {
620 if (cp
-> spawning
&& cp
-> hash
) {
621 class_hash_foreach (cp
-> hash
, write_named_billing_class
);
627 /* Write a spawned class to the database file. */
629 int write_billing_class (class)
635 if (lease_file_is_corrupt
)
636 if (!new_lease_file ())
639 if (!class -> superclass
) {
641 fprintf (db_file
, "\n billing class \"%s\";", class -> name
);
646 fprintf (db_file
, "\n billing subclass \"%s\"",
647 class -> superclass
-> name
);
651 for (i
= 0; i
< class -> hash_string
.len
; i
++)
652 if (!isascii (class -> hash_string
.data
[i
]) ||
653 !isprint (class -> hash_string
.data
[i
]))
655 if (i
== class -> hash_string
.len
) {
657 fprintf (db_file
, " \"%.*s\";",
658 (int)class -> hash_string
.len
,
659 class -> hash_string
.data
);
664 fprintf (db_file
, " %2.2x", class -> hash_string
.data
[0]);
667 for (i
= 1; i
< class -> hash_string
.len
; i
++) {
669 fprintf (db_file
, ":%2.2x",
670 class -> hash_string
.data
[i
]);
675 fprintf (db_file
, ";");
680 class -> dirty
= !errors
;
682 lease_file_is_corrupt
= 1;
686 /* Commit leases after a timeout. */
687 void commit_leases_timeout (void *foo
)
692 /* Commit any leases that have been written out... */
696 /* Commit any outstanding writes to the lease database file.
697 We need to do this even if we're rewriting the file below,
698 just in case the rewrite fails. */
699 if (fflush (db_file
) == EOF
) {
700 log_info ("commit_leases: unable to commit: %m");
703 if (fsync (fileno (db_file
)) < 0) {
704 log_info ("commit_leases: unable to commit: %m");
708 /* If we haven't rewritten the lease database in over an
709 hour, rewrite it now. (The length of time should probably
711 if (count
&& cur_time
- write_time
> 3600) {
713 write_time
= cur_time
;
719 void db_startup (testp
)
724 #if defined (TRACING)
725 if (!trace_playback ()) {
727 /* Read in the existing lease file... */
728 status
= read_conf_file (path_dhcpd_db
,
729 (struct group
*)0, 0, 1);
730 /* XXX ignore status? */
731 #if defined (TRACING)
735 #if defined (TRACING)
736 /* If we're playing back, there is no lease file, so we can't
737 append it, so we create one immediately (maybe this isn't
738 the best solution... */
739 if (trace_playback ()) {
744 db_file
= fopen (path_dhcpd_db
, "a");
746 log_fatal ("Can't open %s for append.", path_dhcpd_db
);
748 #if defined (TRACING)
749 if (trace_playback ())
750 write_time
= cur_time
;
753 GET_TIME (&write_time
);
758 int new_lease_file ()
761 char backfname
[512];
765 /* If we already have an open database, close it. */
771 /* Make a temporary lease file... */
774 /* %Audit% Truncated filename causes panic. %2004.06.17,Safe%
775 * This should never happen since the path is a configuration
776 * variable from build-time or command-line. But if it should,
777 * either by malice or ignorance, we panic, since the potential
780 if (snprintf (newfname
, sizeof newfname
, "%s.%d",
781 path_dhcpd_db
, (int)t
) >= sizeof newfname
)
782 log_fatal("new_lease_file: lease file path too long");
784 db_fd
= open (newfname
, O_WRONLY
| O_TRUNC
| O_CREAT
, 0664);
786 log_error ("Can't create new lease file: %m");
789 if ((db_file
= fdopen (db_fd
, "w")) == NULL
) {
790 log_error ("Can't fdopen new lease file!");
794 /* Write an introduction so people don't complain about time
797 fprintf (db_file
, "# All times in this file are in UTC (GMT), not %s",
798 "your local timezone. This is\n");
801 fprintf (db_file
, "# not a bug, so please don't ask about it. %s",
802 "There is no portable way to\n");
805 fprintf (db_file
, "# store leases in the local timezone, so please %s",
806 "don't request this as a\n");
809 fprintf (db_file
, "# feature. If this is inconvenient or %s",
810 "confusing to you, we sincerely\n");
813 fprintf (db_file
, "# apologize. Seriously, though - don't ask.\n");
816 fprintf (db_file
, "# The format of this file is documented in the %s",
817 "dhcpd.leases(5) manual page.\n");
820 fprintf (db_file
, "# This lease file was written by isc-dhcp-%s\n\n",
825 /* Write out all the leases that we know of... */
827 if (!write_leases ())
830 #if defined (TRACING)
831 if (!trace_playback ()) {
833 /* %Audit% Truncated filename causes panic. %2004.06.17,Safe%
834 * This should never happen since the path is a configuration
835 * variable from build-time or command-line. But if it should,
836 * either by malice or ignorance, we panic, since the potential
837 * for havoc is too high.
839 if (snprintf (backfname
, sizeof backfname
, "%s~", path_dhcpd_db
)
841 log_fatal("new_lease_file: backup lease file path too long");
843 /* Get the old database out of the way... */
844 if (unlink (backfname
) < 0 && errno
!= ENOENT
) {
845 log_error ("Can't remove old lease database backup %s: %m",
849 if (link (path_dhcpd_db
, backfname
) < 0) {
850 log_error ("Can't backup lease database %s to %s: %m",
851 path_dhcpd_db
, backfname
);
854 #if defined (TRACING)
858 /* Move in the new file... */
859 if (rename (newfname
, path_dhcpd_db
) < 0) {
860 log_error ("Can't install new lease database %s to %s: %m",
861 newfname
, path_dhcpd_db
);
866 lease_file_is_corrupt
= 0;
871 lease_file_is_corrupt
= 1;
875 int group_writer (struct group_object
*group
)
877 if (!write_group (group
))
879 if (!commit_leases ())