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