X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/db3f7b6972f3b003c0413b78afcfbe295ffe0b97..afade5fc02622ab0f6c545c723eed0eabaa75284:/src/src/debug.c diff --git a/src/src/debug.c b/src/src/debug.c index 2ddf22907..90c48dde4 100644 --- a/src/src/debug.c +++ b/src/src/debug.c @@ -14,6 +14,34 @@ static int debug_prefix_length = 0; +const uschar * rc_names[] = { /* Mostly for debug output */ + [OK] = US"OK", + [DEFER] = US"DEFER", + [FAIL] = US"FAIL", + [ERROR] = US"ERROR", + [FAIL_FORCED] = US"FAIL_FORCED", + [DECLINE] = US"DECLINE", + [PASS] = US"PASS", + [DISCARD] = US"DISCARD", + [SKIP] = US"SKIP", + [REROUTED] = US"REROUTED", + [PANIC] = US"PANIC", + [BAD64] = US"BAD64", + [UNEXPECTED] = US"UNEXPECTED", + [CANCELLED] = US"CANCELLED", + [FAIL_SEND] = US"FAIL_SEND", + [FAIL_DROP] = US"FAIL_DROP", +}; + +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", +}; + + /************************************************* * Print tree * *************************************************/ @@ -23,8 +51,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. @@ -37,12 +65,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] = '|'; @@ -53,11 +81,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"); } @@ -127,6 +156,17 @@ debug_printf("%s uid=%ld gid=%ld euid=%ld egid=%ld\n", s, (long int)getegid()); } +/************************************************/ + +/* Give a string for a return-code */ + +const uschar * +rc_to_string(int rc) +{ +return rc < 0 || rc >= nelem(rc_names) ? US"?" : rc_names[rc]; +} + + @@ -199,7 +239,7 @@ if (debug_ptr == debug_buffer) if (host_checking && debug_selector == 0) { - Ustrcpy(debug_ptr, ">>> "); + Ustrcpy(debug_ptr, US">>> "); debug_ptr += 4; } @@ -211,30 +251,33 @@ if (indent > 0) for (int i = indent >> 2; i > 0; i--) DEBUG(D_noutf8) { - Ustrcpy(debug_ptr, " !"); + Ustrcpy(debug_ptr, US" !"); debug_ptr += 4; /* 3 spaces + shriek */ debug_prefix_length += 4; } else { - Ustrcpy(debug_ptr, " " UTF8_VERT_2DASH); + Ustrcpy(debug_ptr, US" " UTF8_VERT_2DASH); debug_ptr += 6; /* 3 spaces + 3 UTF-8 octets */ debug_prefix_length += 6; } - Ustrncpy(debug_ptr, " ", indent &= 3); + Ustrncpy(debug_ptr, US" ", indent &= 3); debug_ptr += indent; debug_prefix_length += indent; } -/* Use the checked formatting routine to ensure that the buffer -does not overflow. Ensure there's space for a newline at the end. */ +/* Use the lengthchecked formatting routine to ensure that the buffer +does not overflow. Ensure there's space for a newline at the end. +However, use taint-unchecked routines for writing into the buffer +so that we can write tainted info into the static debug_buffer - +we trust that we will never expand the results. */ { gstring gs = { .size = (int)sizeof(debug_buffer) - 1, .ptr = debug_ptr - debug_buffer, .s = debug_buffer }; - if (!string_vformat(&gs, FALSE, format, ap)) + if (!string_vformat(&gs, SVFMT_TAINT_NOCHK, format, ap)) { uschar * s = US"**** debug string too long - truncated ****\n"; uschar * p = gs.s + gs.ptr; @@ -281,4 +324,88 @@ if (debug_ptr[-1] == '\n') errno = save_errno; } + + +/* Output the details of a socket */ + +void +debug_print_socket(int fd) +{ +struct stat s; +if (fstat(fd, &s) == 0 && (s.st_mode & S_IFMT) == S_IFSOCK) + { + gstring * g = NULL; + int val; + socklen_t vlen = sizeof(val); + 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 * sunp = (struct sockaddr_un *)&a; + + 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_fmt_append(g, " lcl [%s]:%u", + inet_ntoa(sinp->sin_addr), ntohs(sinp->sin_port)); + alen = sizeof(*sinp); + if (getpeername(fd, 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_fmt_append(g, " lcl [%s]:%u", + inet_ntop(AF_INET6, &sin6p->sin6_addr, CS buf, sizeof(buf)), + ntohs(sin6p->sin6_port)); + alen = sizeof(*sin6p); + if (getpeername(fd, 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"); + 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, 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); + break; + } + if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &val, &vlen) == 0) + switch (val) + { + case SOCK_STREAM: g = string_cat(g, US" type SOCK_STREAM"); break; + 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", p->p_name) + : string_fmt_append(g, " proto %d", val); + } +#endif + debug_printf_indent(" socket: %s\n", string_from_gstring(g)); + } +else + debug_printf_indent(" fd st_mode 0%o\n", s.st_mode); +} + + /* End of debug.c */