fixed improper TAILQ fix which caused pluto to segfault
[strongswan.git] / src / pluto / log.c
1 /* error logging functions
2 * Copyright (C) 1997 Angelos D. Keromytis.
3 * Copyright (C) 1998-2001 D. Hugh Redelmeier.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 *
15 * RCSID $Id$
16 */
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <ctype.h>
21 #include <stdarg.h>
22 #include <syslog.h>
23 #include <errno.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include <signal.h> /* used only if MSG_NOSIGNAL not defined */
27 #include <sys/queue.h>
28 #include <libgen.h>
29 #include <sys/stat.h>
30 #include <sys/types.h>
31
32 #include <freeswan.h>
33
34 #include "constants.h"
35 #include "defs.h"
36 #include "log.h"
37 #include "server.h"
38 #include "state.h"
39 #include "connections.h"
40 #include "kernel.h"
41 #include "whack.h" /* needs connections.h */
42 #include "timer.h"
43
44 /* close one per-peer log */
45 static void perpeer_logclose(struct connection *c); /* forward */
46
47
48 bool
49 log_to_stderr = TRUE, /* should log go to stderr? */
50 log_to_syslog = TRUE, /* should log go to syslog? */
51 log_to_perpeer= FALSE; /* should log go to per-IP file? */
52
53 bool
54 logged_txt_warning = FALSE; /* should we complain about finding KEY? */
55
56 /* should we complain when we find no local id */
57 bool
58 logged_myid_fqdn_txt_warning = FALSE,
59 logged_myid_ip_txt_warning = FALSE,
60 logged_myid_fqdn_key_warning = FALSE,
61 logged_myid_ip_key_warning = FALSE;
62
63 /* may include trailing / */
64 const char *base_perpeer_logdir = PERPEERLOGDIR;
65 static int perpeer_count = 0;
66
67 /* from sys/queue.h */
68 static TAILQ_HEAD(perpeer, connection) perpeer_list;
69
70
71 /* Context for logging.
72 *
73 * Global variables: must be carefully adjusted at transaction boundaries!
74 * If the context provides a whack file descriptor, messages
75 * should be copied to it -- see whack_log()
76 */
77 int whack_log_fd = NULL_FD; /* only set during whack_handle() */
78 struct state *cur_state = NULL; /* current state, for diagnostics */
79 struct connection *cur_connection = NULL; /* current connection, for diagnostics */
80 const ip_address *cur_from = NULL; /* source of current current message */
81 u_int16_t cur_from_port; /* host order */
82
83 void
84 init_log(const char *program)
85 {
86 if (log_to_stderr)
87 setbuf(stderr, NULL);
88 if (log_to_syslog)
89 openlog(program, LOG_CONS | LOG_NDELAY | LOG_PID, LOG_AUTHPRIV);
90
91 TAILQ_INIT(&perpeer_list);
92 }
93
94 void
95 close_peerlog(void)
96 {
97 /* exit if the queue has not been initialized */
98 if (perpeer_list.tqh_first == NULL)
99 return;
100
101 /* end of queue is given by pointer to "HEAD" */
102 while (TAILQ_LAST(&perpeer_list, perpeer) != (void *)&perpeer_list)
103 perpeer_logclose(TAILQ_LAST(&perpeer_list, perpeer));
104 }
105
106 void
107 close_log(void)
108 {
109 if (log_to_syslog)
110 closelog();
111
112 close_peerlog();
113 }
114
115 /* Sanitize character string in situ: turns dangerous characters into \OOO.
116 * With a bit of work, we could use simpler reps for \\, \r, etc.,
117 * but this is only to protect against something that shouldn't be used.
118 * Truncate resulting string to what fits in buffer.
119 */
120 static size_t
121 sanitize(char *buf, size_t size)
122 {
123 # define UGLY_WIDTH 4 /* width for ugly character: \OOO */
124 size_t len;
125 size_t added = 0;
126 char *p;
127
128 passert(size >= UGLY_WIDTH); /* need room to swing cat */
129
130 /* find right side of string to be sanitized and count
131 * number of columns to be added. Stop on end of string
132 * or lack of room for more result.
133 */
134 for (p = buf; *p != '\0' && &p[added] < &buf[size - UGLY_WIDTH]; )
135 {
136 unsigned char c = *p++;
137
138 if (c == '\\' || !isprint(c))
139 added += UGLY_WIDTH - 1;
140 }
141
142 /* at this point, p points after last original character to be
143 * included. added is how many characters are added to sanitize.
144 * so p[added] will point after last sanitized character.
145 */
146
147 p[added] = '\0';
148 len = &p[added] - buf;
149
150 /* scan backwards, copying characters to their new home
151 * and inserting the expansions for ugly characters.
152 * It is finished when no more shifting is required.
153 * This is a predecrement loop.
154 */
155 while (added != 0)
156 {
157 char fmtd[UGLY_WIDTH + 1];
158 unsigned char c;
159
160 while ((c = *--p) != '\\' && isprint(c))
161 p[added] = c;
162 added -= UGLY_WIDTH - 1;
163 snprintf(fmtd, sizeof(fmtd), "\\%03o", c);
164 memcpy(p + added, fmtd, UGLY_WIDTH);
165 }
166 return len;
167 # undef UGLY_WIDTH
168 }
169
170 /* format a string for the log, with suitable prefixes.
171 * A format starting with ~ indicates that this is a reprocessing
172 * of the message, so prefixing and quoting is suppressed.
173 */
174 static void
175 fmt_log(char *buf, size_t buf_len, const char *fmt, va_list ap)
176 {
177 bool reproc = *fmt == '~';
178 size_t ps;
179 struct connection *c = cur_state != NULL ? cur_state->st_connection
180 : cur_connection;
181
182 buf[0] = '\0';
183 if (reproc)
184 fmt++; /* ~ at start of format suppresses this prefix */
185 else if (c != NULL)
186 {
187 /* start with name of connection */
188 char *const be = buf + buf_len;
189 char *bp = buf;
190
191 snprintf(bp, be - bp, "\"%s\"", c->name);
192 bp += strlen(bp);
193
194 /* if it fits, put in any connection instance information */
195 if (be - bp > CONN_INST_BUF)
196 {
197 fmt_conn_instance(c, bp);
198 bp += strlen(bp);
199 }
200
201 if (cur_state != NULL)
202 {
203 /* state number */
204 snprintf(bp, be - bp, " #%lu", cur_state->st_serialno);
205 bp += strlen(bp);
206 }
207 snprintf(bp, be - bp, ": ");
208 }
209 else if (cur_from != NULL)
210 {
211 /* peer's IP address */
212 /* Note: must not use ip_str() because our caller might! */
213 char ab[ADDRTOT_BUF];
214
215 (void) addrtot(cur_from, 0, ab, sizeof(ab));
216 snprintf(buf, buf_len, "packet from %s:%u: "
217 , ab, (unsigned)cur_from_port);
218 }
219
220 ps = strlen(buf);
221 vsnprintf(buf + ps, buf_len - ps, fmt, ap);
222 if (!reproc)
223 (void)sanitize(buf, buf_len);
224 }
225
226 static void
227 perpeer_logclose(struct connection *c)
228 {
229 /* only free/close things if we had used them! */
230 if (c->log_file != NULL)
231 {
232 passert(perpeer_count > 0);
233
234 TAILQ_REMOVE(&perpeer_list, c, log_link);
235 perpeer_count--;
236 fclose(c->log_file);
237 c->log_file=NULL;
238 }
239 }
240
241 void
242 perpeer_logfree(struct connection *c)
243 {
244 perpeer_logclose(c);
245 if (c->log_file_name != NULL)
246 {
247 pfree(c->log_file_name);
248 c->log_file_name = NULL;
249 c->log_file_err = FALSE;
250 }
251 }
252
253 /* open the per-peer log */
254 static void
255 open_peerlog(struct connection *c)
256 {
257 syslog(LOG_INFO, "opening log file for conn %s", c->name);
258
259 if (c->log_file_name == NULL)
260 {
261 char peername[ADDRTOT_BUF], dname[ADDRTOT_BUF];
262 int peernamelen, lf_len;
263
264 addrtot(&c->spd.that.host_addr, 'Q', peername, sizeof(peername));
265 peernamelen = strlen(peername);
266
267 /* copy IP address, turning : and . into / */
268 {
269 char c, *p, *q;
270
271 p = peername;
272 q = dname;
273 do {
274 c = *p++;
275 if (c == '.' || c == ':')
276 c = '/';
277 *q++ = c;
278 } while (c != '\0');
279 }
280
281 lf_len = peernamelen * 2
282 + strlen(base_perpeer_logdir)
283 + sizeof("//.log")
284 + 1;
285 c->log_file_name = alloc_bytes(lf_len, "per-peer log file name");
286
287 fprintf(stderr, "base dir |%s| dname |%s| peername |%s|"
288 , base_perpeer_logdir, dname, peername);
289 snprintf(c->log_file_name, lf_len, "%s/%s/%s.log"
290 , base_perpeer_logdir, dname, peername);
291
292 syslog(LOG_DEBUG, "conn %s logfile is %s", c->name, c->log_file_name);
293 }
294
295 /* now open the file, creating directories if necessary */
296
297 { /* create the directory */
298 char *dname;
299 int bpl_len = strlen(base_perpeer_logdir);
300 char *slashloc;
301
302 dname = clone_str(c->log_file_name, "temp copy of file name");
303 dname = dirname(dname);
304
305 if (access(dname, W_OK) != 0)
306 {
307 if (errno != ENOENT)
308 {
309 if (c->log_file_err)
310 {
311 syslog(LOG_CRIT, "can not write to %s: %s"
312 , dname, strerror(errno));
313 c->log_file_err = TRUE;
314 pfree(dname);
315 return;
316 }
317 }
318
319 /* directory does not exist, walk path creating dirs */
320 /* start at base_perpeer_logdir */
321 slashloc = dname + bpl_len;
322 slashloc++; /* since, by construction there is a slash
323 right there */
324
325 while (*slashloc != '\0')
326 {
327 char saveslash;
328
329 /* look for next slash */
330 while (*slashloc != '\0' && *slashloc != '/') slashloc++;
331
332 saveslash = *slashloc;
333
334 *slashloc = '\0';
335
336 if (mkdir(dname, 0750) != 0 && errno != EEXIST)
337 {
338 syslog(LOG_CRIT, "can not create dir %s: %s"
339 , dname, strerror(errno));
340 c->log_file_err = TRUE;
341 pfree(dname);
342 return;
343 }
344 syslog(LOG_DEBUG, "created new directory %s", dname);
345 *slashloc = saveslash;
346 slashloc++;
347 }
348 }
349
350 pfree(dname);
351 }
352
353 c->log_file = fopen(c->log_file_name, "a");
354 if (c->log_file == NULL)
355 {
356 if (c->log_file_err)
357 {
358 syslog(LOG_CRIT, "logging system can not open %s: %s"
359 , c->log_file_name, strerror(errno));
360 c->log_file_err = TRUE;
361 }
362 return;
363 }
364
365 /* look for a connection to close! */
366 while (perpeer_count >= MAX_PEERLOG_COUNT)
367 {
368 /* can not be NULL because perpeer_count > 0 */
369 passert(TAILQ_LAST(&perpeer_list, perpeer) != (void *)&perpeer_list);
370
371 perpeer_logclose(TAILQ_LAST(&perpeer_list, perpeer));
372 }
373
374 /* insert this into the list */
375 TAILQ_INSERT_HEAD(&perpeer_list, c, log_link);
376 passert(c->log_file != NULL);
377 perpeer_count++;
378 }
379
380 /* log a line to cur_connection's log */
381 static void
382 peerlog(const char *prefix, const char *m)
383 {
384 if (cur_connection == NULL)
385 {
386 /* we can not log it in this case. Oh well. */
387 return;
388 }
389
390 if (cur_connection->log_file == NULL)
391 {
392 open_peerlog(cur_connection);
393 }
394
395 /* despite our attempts above, we may not be able to open the file. */
396 if (cur_connection->log_file != NULL)
397 {
398 char datebuf[32];
399 time_t n;
400 struct tm *t;
401
402 time(&n);
403 t = localtime(&n);
404
405 strftime(datebuf, sizeof(datebuf), "%Y-%m-%d %T", t);
406 fprintf(cur_connection->log_file, "%s %s%s\n", datebuf, prefix, m);
407
408 /* now move it to the front of the list */
409 TAILQ_REMOVE(&perpeer_list, cur_connection, log_link);
410 TAILQ_INSERT_HEAD(&perpeer_list, cur_connection, log_link);
411 }
412 }
413
414 void
415 plog(const char *message, ...)
416 {
417 va_list args;
418 char m[LOG_WIDTH]; /* longer messages will be truncated */
419
420 va_start(args, message);
421 fmt_log(m, sizeof(m), message, args);
422 va_end(args);
423
424 if (log_to_stderr)
425 fprintf(stderr, "%s\n", m);
426 if (log_to_syslog)
427 syslog(LOG_WARNING, "%s", m);
428 if (log_to_perpeer)
429 peerlog("", m);
430
431 whack_log(RC_LOG, "~%s", m);
432 }
433
434 void
435 loglog(int mess_no, const char *message, ...)
436 {
437 va_list args;
438 char m[LOG_WIDTH]; /* longer messages will be truncated */
439
440 va_start(args, message);
441 fmt_log(m, sizeof(m), message, args);
442 va_end(args);
443
444 if (log_to_stderr)
445 fprintf(stderr, "%s\n", m);
446 if (log_to_syslog)
447 syslog(LOG_WARNING, "%s", m);
448 if (log_to_perpeer)
449 peerlog("", m);
450
451 whack_log(mess_no, "~%s", m);
452 }
453
454 void
455 log_errno_routine(int e, const char *message, ...)
456 {
457 va_list args;
458 char m[LOG_WIDTH]; /* longer messages will be truncated */
459
460 va_start(args, message);
461 fmt_log(m, sizeof(m), message, args);
462 va_end(args);
463
464 if (log_to_stderr)
465 fprintf(stderr, "ERROR: %s. Errno %d: %s\n", m, e, strerror(e));
466 if (log_to_syslog)
467 syslog(LOG_ERR, "ERROR: %s. Errno %d: %s", m, e, strerror(e));
468 if (log_to_perpeer)
469 {
470 peerlog(strerror(e), m);
471 }
472
473 whack_log(RC_LOG_SERIOUS
474 , "~ERROR: %s. Errno %d: %s", m, e, strerror(e));
475 }
476
477 void
478 exit_log(const char *message, ...)
479 {
480 va_list args;
481 char m[LOG_WIDTH]; /* longer messages will be truncated */
482
483 va_start(args, message);
484 fmt_log(m, sizeof(m), message, args);
485 va_end(args);
486
487 if (log_to_stderr)
488 fprintf(stderr, "FATAL ERROR: %s\n", m);
489 if (log_to_syslog)
490 syslog(LOG_ERR, "FATAL ERROR: %s", m);
491 if (log_to_perpeer)
492 peerlog("FATAL ERROR: ", m);
493
494 whack_log(RC_LOG_SERIOUS, "~FATAL ERROR: %s", m);
495
496 exit_pluto(1);
497 }
498
499 void
500 exit_log_errno_routine(int e, const char *message, ...)
501 {
502 va_list args;
503 char m[LOG_WIDTH]; /* longer messages will be truncated */
504
505 va_start(args, message);
506 fmt_log(m, sizeof(m), message, args);
507 va_end(args);
508
509 if (log_to_stderr)
510 fprintf(stderr, "FATAL ERROR: %s. Errno %d: %s\n", m, e, strerror(e));
511 if (log_to_syslog)
512 syslog(LOG_ERR, "FATAL ERROR: %s. Errno %d: %s", m, e, strerror(e));
513 if (log_to_perpeer)
514 peerlog(strerror(e), m);
515
516 whack_log(RC_LOG_SERIOUS
517 , "~FATAL ERROR: %s. Errno %d: %s", m, e, strerror(e));
518
519 exit_pluto(1);
520 }
521
522 /* emit message to whack.
523 * form is "ddd statename text" where
524 * - ddd is a decimal status code (RC_*) as described in whack.h
525 * - text is a human-readable annotation
526 */
527 #ifdef DEBUG
528 static volatile sig_atomic_t dying_breath = FALSE;
529 #endif
530
531 void
532 whack_log(int mess_no, const char *message, ...)
533 {
534 int wfd = whack_log_fd != NULL_FD ? whack_log_fd
535 : cur_state != NULL ? cur_state->st_whack_sock
536 : NULL_FD;
537
538 if (wfd != NULL_FD
539 #ifdef DEBUG
540 || dying_breath
541 #endif
542 )
543 {
544 va_list args;
545 char m[LOG_WIDTH]; /* longer messages will be truncated */
546 int prelen = snprintf(m, sizeof(m), "%03d ", mess_no);
547
548 passert(prelen >= 0);
549
550 va_start(args, message);
551 fmt_log(m+prelen, sizeof(m)-prelen, message, args);
552 va_end(args);
553
554 #if DEBUG
555 if (dying_breath)
556 {
557 /* status output copied to log */
558 if (log_to_stderr)
559 fprintf(stderr, "%s\n", m + prelen);
560 if (log_to_syslog)
561 syslog(LOG_WARNING, "%s", m + prelen);
562 if (log_to_perpeer)
563 peerlog("", m);
564 }
565 #endif
566
567 if (wfd != NULL_FD)
568 {
569 /* write to whack socket, but suppress possible SIGPIPE */
570 size_t len = strlen(m);
571 #ifdef MSG_NOSIGNAL /* depends on version of glibc??? */
572 m[len] = '\n'; /* don't need NUL, do need NL */
573 (void) send(wfd, m, len + 1, MSG_NOSIGNAL);
574 #else /* !MSG_NOSIGNAL */
575 int r;
576 struct sigaction act
577 , oldact;
578
579 m[len] = '\n'; /* don't need NUL, do need NL */
580 act.sa_handler = SIG_IGN;
581 sigemptyset(&act.sa_mask);
582 act.sa_flags = 0; /* no nothing */
583 r = sigaction(SIGPIPE, &act, &oldact);
584 passert(r == 0);
585
586 (void) write(wfd, m, len + 1);
587
588 r = sigaction(SIGPIPE, &oldact, NULL);
589 passert(r == 0);
590 #endif /* !MSG_NOSIGNAL */
591 }
592 }
593 }
594
595 /* Build up a diagnostic in a static buffer.
596 * Although this would be a generally useful function, it is very
597 * hard to come up with a discipline that prevents different uses
598 * from interfering. It is intended that by limiting it to building
599 * diagnostics, we will avoid this problem.
600 * Juggling is performed to allow an argument to be a previous
601 * result: the new string may safely depend on the old one. This
602 * restriction is not checked in any way: violators will produce
603 * confusing results (without crashing!).
604 */
605 char diag_space[sizeof(diag_space)];
606
607 err_t
608 builddiag(const char *fmt, ...)
609 {
610 static char diag_space[LOG_WIDTH]; /* longer messages will be truncated */
611 char t[sizeof(diag_space)]; /* build result here first */
612 va_list args;
613
614 va_start(args, fmt);
615 t[0] = '\0'; /* in case nothing terminates string */
616 vsnprintf(t, sizeof(t), fmt, args);
617 va_end(args);
618 strcpy(diag_space, t);
619 return diag_space;
620 }
621
622 /* Debugging message support */
623
624 #ifdef DEBUG
625
626 void
627 switch_fail(int n, const char *file_str, unsigned long line_no)
628 {
629 char buf[30];
630
631 snprintf(buf, sizeof(buf), "case %d unexpected", n);
632 passert_fail(buf, file_str, line_no);
633 }
634
635 void
636 passert_fail(const char *pred_str, const char *file_str, unsigned long line_no)
637 {
638 /* we will get a possibly unplanned prefix. Hope it works */
639 loglog(RC_LOG_SERIOUS, "ASSERTION FAILED at %s:%lu: %s", file_str, line_no, pred_str);
640 if (!dying_breath)
641 {
642 dying_breath = TRUE;
643 show_status(TRUE, NULL);
644 }
645 abort(); /* exiting correctly doesn't always work */
646 }
647
648 void
649 pexpect_log(const char *pred_str, const char *file_str, unsigned long line_no)
650 {
651 /* we will get a possibly unplanned prefix. Hope it works */
652 loglog(RC_LOG_SERIOUS, "EXPECTATION FAILED at %s:%lu: %s", file_str, line_no, pred_str);
653 }
654
655 lset_t
656 base_debugging = DBG_NONE, /* default to reporting nothing */
657 cur_debugging = DBG_NONE;
658
659 void
660 extra_debugging(const struct connection *c)
661 {
662 if(c == NULL)
663 {
664 reset_debugging();
665 return;
666 }
667
668 if (c!= NULL && c->extra_debugging != 0)
669 {
670 plog("enabling for connection: %s"
671 , bitnamesof(debug_bit_names, c->extra_debugging & ~cur_debugging));
672 cur_debugging |= c->extra_debugging;
673 }
674 }
675
676 /* log a debugging message (prefixed by "| ") */
677
678 void
679 DBG_log(const char *message, ...)
680 {
681 va_list args;
682 char m[LOG_WIDTH]; /* longer messages will be truncated */
683
684 va_start(args, message);
685 vsnprintf(m, sizeof(m), message, args);
686 va_end(args);
687
688 (void)sanitize(m, sizeof(m));
689
690 if (log_to_stderr)
691 fprintf(stderr, "| %s\n", m);
692 if (log_to_syslog)
693 syslog(LOG_DEBUG, "| %s", m);
694 if (log_to_perpeer)
695 peerlog("| ", m);
696 }
697
698 /* dump raw bytes in hex to stderr (for lack of any better destination) */
699
700 void
701 DBG_dump(const char *label, const void *p, size_t len)
702 {
703 # define DUMP_LABEL_WIDTH 20 /* arbitrary modest boundary */
704 # define DUMP_WIDTH (4 * (1 + 4 * 3) + 1)
705 char buf[DUMP_LABEL_WIDTH + DUMP_WIDTH];
706 char *bp;
707 const unsigned char *cp = p;
708
709 bp = buf;
710
711 if (label != NULL && label[0] != '\0')
712 {
713 /* Handle the label. Care must be taken to avoid buffer overrun. */
714 size_t llen = strlen(label);
715
716 if (llen + 1 > sizeof(buf))
717 {
718 DBG_log("%s", label);
719 }
720 else
721 {
722 strcpy(buf, label);
723 if (buf[llen-1] == '\n')
724 {
725 buf[llen-1] = '\0'; /* get rid of newline */
726 DBG_log("%s", buf);
727 }
728 else if (llen < DUMP_LABEL_WIDTH)
729 {
730 bp = buf + llen;
731 }
732 else
733 {
734 DBG_log("%s", buf);
735 }
736 }
737 }
738
739 do {
740 int i, j;
741
742 for (i = 0; len!=0 && i!=4; i++)
743 {
744 *bp++ = ' ';
745 for (j = 0; len!=0 && j!=4; len--, j++)
746 {
747 static const char hexdig[] = "0123456789abcdef";
748
749 *bp++ = ' ';
750 *bp++ = hexdig[(*cp >> 4) & 0xF];
751 *bp++ = hexdig[*cp & 0xF];
752 cp++;
753 }
754 }
755 *bp = '\0';
756 DBG_log("%s", buf);
757 bp = buf;
758 } while (len != 0);
759 # undef DUMP_LABEL_WIDTH
760 # undef DUMP_WIDTH
761 }
762
763 #endif /* DEBUG */
764
765 void
766 show_status(bool all, const char *name)
767 {
768 if (all)
769 {
770 show_ifaces_status();
771 show_myid_status();
772 show_debug_status();
773 whack_log(RC_COMMENT, BLANK_FORMAT); /* spacer */
774 }
775 show_connections_status(all, name);
776 show_states_status(all, name);
777 #ifdef KLIPS
778 show_shunt_status();
779 #endif
780 }
781
782 /* ip_str: a simple to use variant of addrtot.
783 * It stores its result in a static buffer.
784 * This means that newer calls overwrite the storage of older calls.
785 * Note: this is not used in any of the logging functions, so their
786 * callers may use it.
787 */
788 const char *
789 ip_str(const ip_address *src)
790 {
791 static char buf[ADDRTOT_BUF];
792
793 addrtot(src, 0, buf, sizeof(buf));
794 return buf;
795 }
796
797 /*
798 * a routine that attempts to schedule itself daily.
799 *
800 */
801
802 void
803 daily_log_reset(void)
804 {
805 /* now perform actions */
806 logged_txt_warning = FALSE;
807
808 logged_myid_fqdn_txt_warning = FALSE;
809 logged_myid_ip_txt_warning = FALSE;
810 logged_myid_fqdn_key_warning = FALSE;
811 logged_myid_ip_key_warning = FALSE;
812 }
813
814 void
815 daily_log_event(void)
816 {
817 struct tm *ltime;
818 time_t n, interval;
819
820 /* attempt to schedule oneself to midnight, local time
821 * do this by getting seconds in the day, and delaying
822 * by 86400 - hour*3600+minutes*60+seconds.
823 */
824 time(&n);
825 ltime = localtime(&n);
826 interval = (24 * 60 * 60)
827 - (ltime->tm_sec
828 + ltime->tm_min * 60
829 + ltime->tm_hour * 3600);
830
831 event_schedule(EVENT_LOG_DAILY, interval, NULL);
832
833 daily_log_reset();
834 }
835
836 /*
837 * Local Variables:
838 * c-basic-offset:4
839 * c-style: pluto
840 * End:
841 */