X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/a8e46b3b7147d214072bc34beff184724f3f2be6..1d28cc061677bd07d9bed48dd84bd5c590247043:/src/src/debug.c diff --git a/src/src/debug.c b/src/src/debug.c index 806573f1c..44ad763e1 100644 --- a/src/src/debug.c +++ b/src/src/debug.c @@ -2,8 +2,10 @@ * Exim - an Internet mail transport agent * *************************************************/ +/* Copyright (c) The Exim Maintainers 2015 - 2022 */ /* Copyright (c) University of Cambridge 1995 - 2018 */ /* See the file NOTICE for conditions of use and distribution. */ +/* SPDX-License-Identifier: GPL-2.0-or-later */ #include "exim.h" @@ -12,6 +14,8 @@ static uschar debug_buffer[2048]; static uschar *debug_ptr = debug_buffer; static int debug_prefix_length = 0; +static unsigned pretrigger_writeoff; +static unsigned pretrigger_readoff; const uschar * rc_names[] = { /* Mostly for debug output */ @@ -30,7 +34,16 @@ const uschar * rc_names[] = { /* Mostly for debug output */ [UNEXPECTED] = US"UNEXPECTED", [CANCELLED] = US"CANCELLED", [FAIL_SEND] = US"FAIL_SEND", - [FAIL_DROP] = US"FAIL_DROP" + [FAIL_DROP] = US"FAIL_DROP", + [DANE] = US"DANE", +}; + +const uschar * dns_rc_names[] = { + [DNS_SUCCEED] = US"DNS_SUCCEED", + [DNS_NOMATCH] = US"DNS_NOMATCH", + [DNS_NODATA] = US"DNS_NODATA", + [DNS_AGAIN] = US"DNS_AGAIN", + [DNS_FAIL] = US"DNS_FAIL", }; @@ -43,8 +56,8 @@ hold the line-drawing characters that need to be printed on every line as it moves down the page. This function is used only in debugging circumstances. The output is done via debug_printf(). */ -#define tree_printlinesize 132 /* line size for printing */ -static uschar tree_printline[tree_printlinesize]; +#define TREE_PRINTLINESIZE 132 /* line size for printing */ +static uschar tree_printline[TREE_PRINTLINESIZE]; /* Internal recursive subroutine. @@ -57,12 +70,12 @@ Returns: nothing */ static void -tree_printsub(tree_node *p, int pos, int barswitch) +tree_printsub(tree_node * p, int pos, int barswitch) { if (p->right) tree_printsub(p->right, pos+2, 1); -for (int i = 0; i <= pos-1; i++) debug_printf("%c", tree_printline[i]); -debug_printf("-->%s [%d]\n", p->name, p->balance); -tree_printline[pos] = barswitch? '|' : ' '; +for (int i = 0; i <= pos-1; i++) debug_printf_indent(" %c", tree_printline[i]); +debug_printf_indent(" -->%s [%d]\n", p->name, p->balance); +tree_printline[pos] = barswitch ? '|' : ' '; if (p->left) { tree_printline[pos+2] = '|'; @@ -73,11 +86,12 @@ if (p->left) /* The external function, with just a tree node argument. */ void -debug_print_tree(tree_node *p) +debug_print_tree(const char * title, tree_node * p) { -for (int i = 0; i < tree_printlinesize; i++) tree_printline[i] = ' '; -if (!p) debug_printf("Empty Tree\n"); else tree_printsub(p, 0, 0); -debug_printf("---- End of tree ----\n"); +debug_printf_indent("%s:\n", title); +for (int i = 0; i < TREE_PRINTLINESIZE; i++) tree_printline[i] = ' '; +if (!p) debug_printf_indent(" Empty Tree\n"); else tree_printsub(p, 0, 0); +debug_printf_indent("---- End of tree ----\n"); } @@ -307,8 +321,41 @@ if (debug_ptr[-1] == '\n') } } - fprintf(debug_file, "%s", CS debug_buffer); - fflush(debug_file); + if (debug_pretrigger_buf) + { + int needed = Ustrlen(debug_buffer)+1, avail; + char c; + + if (needed > debug_pretrigger_bsize) + needed = debug_pretrigger_bsize; + if ((avail = pretrigger_readoff - pretrigger_writeoff) <= 0) + avail += debug_pretrigger_bsize; + + /* We have a pretrigger set up, trigger not yet hit. Copy the line(s) to the + pretrig buffer, dropping earlier lines if needed but truncating this line if + the pbuf is maxed out. In the PTB the lines are NOT nul-terminated. */ + + while (avail < needed) + do + { + avail++; + c = debug_pretrigger_buf[pretrigger_readoff]; + if (++pretrigger_readoff >= debug_pretrigger_bsize) pretrigger_readoff = 0; + } + while (c && c != '\n' && pretrigger_readoff != pretrigger_writeoff); + + needed--; + for (int i = 0; needed; i++, needed--) + { + debug_pretrigger_buf[pretrigger_writeoff] = debug_buffer[i]; + if (++pretrigger_writeoff >= debug_pretrigger_bsize) pretrigger_writeoff = 0; + } + } + else + { + fprintf(debug_file, "%s", CS debug_buffer); + fflush(debug_file); + } debug_ptr = debug_buffer; debug_prefix_length = 0; } @@ -328,48 +375,52 @@ if (fstat(fd, &s) == 0 && (s.st_mode & S_IFMT) == S_IFSOCK) gstring * g = NULL; int val; socklen_t vlen = sizeof(val); - struct sockaddr a; + struct sockaddr_storage a; socklen_t alen = sizeof(a); struct sockaddr_in * sinp = (struct sockaddr_in *)&a; struct sockaddr_in6 * sin6p = (struct sockaddr_in6 *)&a; - struct sockaddr_un * sa_unp ; (struct sockaddr_un *)&a; + struct sockaddr_un * sunp = (struct sockaddr_un *)&a; - if (getsockname(fd, &a, &alen) == 0) - switch (sinp->sin_family) + if (getsockname(fd, (struct sockaddr*)&a, &alen) == 0) + switch (a.ss_family) { case AF_INET: - g = string_cat(g, US" domain AF_INET"); + g = string_cat(g, US"domain AF_INET"); g = string_fmt_append(g, " lcl [%s]:%u", inet_ntoa(sinp->sin_addr), ntohs(sinp->sin_port)); - if (getpeername(fd, &a, &alen) == 0) + alen = sizeof(*sinp); + if (getpeername(fd, (struct sockaddr *)sinp, &alen) == 0) g = string_fmt_append(g, " rmt [%s]:%u", inet_ntoa(sinp->sin_addr), ntohs(sinp->sin_port)); break; case AF_INET6: { uschar buf[46]; - g = string_cat(g, US" domain AF_INET6"); + g = string_cat(g, US"domain AF_INET6"); g = string_fmt_append(g, " lcl [%s]:%u", inet_ntop(AF_INET6, &sin6p->sin6_addr, CS buf, sizeof(buf)), ntohs(sin6p->sin6_port)); - if (getpeername(fd, &a, &alen) == 0) + alen = sizeof(*sin6p); + if (getpeername(fd, (struct sockaddr *)sin6p, &alen) == 0) g = string_fmt_append(g, " rmt [%s]:%u", inet_ntop(AF_INET6, &sin6p->sin6_addr, CS buf, sizeof(buf)), ntohs(sin6p->sin6_port)); break; } case AF_UNIX: - g = string_cat(g, US" domain AF_UNIX"); - g = string_fmt_append(g, " lcl %s%s", - sa_unp->sun_path[0] ? US"" : US"@", - sa_unp->sun_path[0] ? sa_unp->sun_path : sa_unp->sun_path+1); - if (getpeername(fd, &a, &alen) == 0) - g = string_fmt_append(g, " rmt %s%s", - sa_unp->sun_path[0] ? US"" : US"@", - sa_unp->sun_path[0] ? sa_unp->sun_path : sa_unp->sun_path+1); - break; + g = string_cat(g, US"domain AF_UNIX"); + if (alen > sizeof(sa_family_t)) /* not unix(7) "unnamed socket" */ + g = string_fmt_append(g, " lcl %s%s", + sunp->sun_path[0] ? US"" : US"@", + sunp->sun_path[0] ? sunp->sun_path : sunp->sun_path+1); + alen = sizeof(*sunp); + if (getpeername(fd, (struct sockaddr *)sunp, &alen) == 0) + g = string_fmt_append(g, " rmt %s%s", + sunp->sun_path[0] ? US"" : US"@", + sunp->sun_path[0] ? sunp->sun_path : sunp->sun_path+1); + break; default: - g = string_fmt_append(g, " domain %u", sinp->sin_family); + g = string_fmt_append(g, "domain %u", sinp->sin_family); break; } if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &val, &vlen) == 0) @@ -379,13 +430,15 @@ if (fstat(fd, &s) == 0 && (s.st_mode & S_IFMT) == S_IFSOCK) case SOCK_DGRAM: g = string_cat(g, US" type SOCK_DGRAM"); break; default: g = string_fmt_append(g, " type %d", val); break; } +#ifdef SO_PROTOCOL if (getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, &val, &vlen) == 0) { struct protoent * p = getprotobynumber(val); g = p - ? string_fmt_append(g, " proto %s\n", p->p_name) + ? string_fmt_append(g, " proto %s", p->p_name) : string_fmt_append(g, " proto %d", val); } +#endif debug_printf_indent(" socket: %s\n", string_from_gstring(g)); } else @@ -393,4 +446,54 @@ else } +/**************************************************************/ +/* Pretrigger handling for debug. The debug_printf implementation +diverts output to a circular buffer if the buffer is set up. +The routines here set up the buffer, and unload it to file (and release it). +What ends up in the buffer is subject to the usual debug_selector. */ + +void +debug_pretrigger_setup(const uschar * size_string) +{ +long size = Ustrtol(size_string, NULL, 0); +if (size > 0) + { + unsigned bufsize = MIN(size, 16384); + + dtrigger_selector |= BIT(DTi_pretrigger); + if (debug_pretrigger_buf) store_free(debug_pretrigger_buf); + debug_pretrigger_buf = store_malloc((size_t)(debug_pretrigger_bsize = bufsize)); + pretrigger_readoff = pretrigger_writeoff = 0; + } +} + +void +debug_trigger_fire(void) +{ +int nbytes; + +if (!debug_pretrigger_buf) return; + +if (debug_file && (nbytes = pretrigger_writeoff - pretrigger_readoff) != 0) + if (nbytes > 0) + fwrite(debug_pretrigger_buf + pretrigger_readoff, 1, nbytes, debug_file); + else + { + fwrite(debug_pretrigger_buf + pretrigger_readoff, 1, + debug_pretrigger_bsize - pretrigger_readoff, debug_file); + fwrite(debug_pretrigger_buf, 1, pretrigger_writeoff, debug_file); + } + +debug_pretrigger_discard(); +} + +void +debug_pretrigger_discard(void) +{ +if (debug_pretrigger_buf) store_free(debug_pretrigger_buf); +debug_pretrigger_buf = NULL; +dtrigger_selector = 0; +} + + /* End of debug.c */