1 /*************************************************
2 * Exim - an Internet mail transport agent *
3 *************************************************/
5 /* Copyright (c) University of Cambridge 1995 - 2018 */
6 /* See the file NOTICE for conditions of use and distribution. */
11 static uschar debug_buffer[2048];
12 static uschar *debug_ptr = debug_buffer;
13 static int debug_prefix_length = 0;
17 const uschar * rc_names[] = { /* Mostly for debug output */
22 [FAIL_FORCED] = US"FAIL_FORCED",
23 [DECLINE] = US"DECLINE",
25 [DISCARD] = US"DISCARD",
27 [REROUTED] = US"REROUTED",
30 [UNEXPECTED] = US"UNEXPECTED",
31 [CANCELLED] = US"CANCELLED",
32 [FAIL_SEND] = US"FAIL_SEND",
33 [FAIL_DROP] = US"FAIL_DROP",
37 const uschar * dns_rc_names[] = {
38 [DNS_SUCCEED] = US"DNS_SUCCEED",
39 [DNS_NOMATCH] = US"DNS_NOMATCH",
40 [DNS_NODATA] = US"DNS_NODATA",
41 [DNS_AGAIN] = US"DNS_AGAIN",
42 [DNS_FAIL] = US"DNS_FAIL",
46 /*************************************************
48 *************************************************/
50 /* Recursive tree-printing subroutine. It uses a static vector of uschar to
51 hold the line-drawing characters that need to be printed on every line as it
52 moves down the page. This function is used only in debugging circumstances. The
53 output is done via debug_printf(). */
55 #define TREE_PRINTLINESIZE 132 /* line size for printing */
56 static uschar tree_printline[TREE_PRINTLINESIZE];
58 /* Internal recursive subroutine.
62 pos amount of indenting & vertical bars to print
63 barswitch if TRUE print | at the pos value
69 tree_printsub(tree_node * p, int pos, int barswitch)
71 if (p->right) tree_printsub(p->right, pos+2, 1);
72 for (int i = 0; i <= pos-1; i++) debug_printf_indent(" %c", tree_printline[i]);
73 debug_printf_indent(" -->%s [%d]\n", p->name, p->balance);
74 tree_printline[pos] = barswitch ? '|' : ' ';
77 tree_printline[pos+2] = '|';
78 tree_printsub(p->left, pos+2, 0);
82 /* The external function, with just a tree node argument. */
85 debug_print_tree(const char * title, tree_node * p)
87 debug_printf_indent("%s:\n", title);
88 for (int i = 0; i < TREE_PRINTLINESIZE; i++) tree_printline[i] = ' ';
89 if (!p) debug_printf_indent(" Empty Tree\n"); else tree_printsub(p, 0, 0);
90 debug_printf_indent("---- End of tree ----\n");
95 /*************************************************
96 * Print an argv vector *
97 *************************************************/
99 /* Called when about to obey execv().
101 Argument: the argv vector
106 debug_print_argv(const uschar ** argv)
108 debug_printf("exec");
109 while (*argv) debug_printf(" %.256s", *argv++);
115 /*************************************************
116 * Expand and print debugging string *
117 *************************************************/
119 /* The string is expanded and written as debugging output. If
120 expansion fails, a message is written instead.
127 debug_print_string(uschar *debug_string)
129 if (!debug_string) return;
132 uschar *s = expand_string(debug_string);
134 debug_printf("failed to expand debug_output \"%s\": %s\n", debug_string,
135 expand_string_message);
137 debug_printf("%s%s", s, (s[Ustrlen(s)-1] == '\n')? "" : "\n");
143 /*************************************************
144 * Print current uids and gids *
145 *************************************************/
148 Argument: an introductory string
153 debug_print_ids(uschar *s)
155 debug_printf("%s uid=%ld gid=%ld euid=%ld egid=%ld\n", s,
156 (long int)getuid(), (long int)getgid(), (long int)geteuid(),
157 (long int)getegid());
160 /************************************************/
162 /* Give a string for a return-code */
167 return rc < 0 || rc >= nelem(rc_names) ? US"?" : rc_names[rc];
174 /*************************************************
175 * Print debugging message *
176 *************************************************/
178 /* There are two entries, one for use when being called directly from a
179 function with a variable argument list, one for prepending an indent.
181 If debug_pid is nonzero, print the pid at the start of each line. This is for
182 tidier output when running parallel remote deliveries with debugging turned on.
183 Must do the whole thing with a single printf and flush, as otherwise output may
184 get interleaved. Since some calls to debug_printf() don't end with newline,
185 we save up the text until we do get the newline.
186 Take care to not disturb errno. */
189 /* Debug printf indented by ACL nest depth */
191 debug_printf_indent(const char * format, ...)
194 va_start(ap, format);
195 debug_vprintf(acl_level + expand_level, format, ap);
200 debug_printf(const char *format, ...)
203 va_start(ap, format);
204 debug_vprintf(0, format, ap);
209 debug_vprintf(int indent, const char *format, va_list ap)
211 int save_errno = errno;
213 if (!debug_file) return;
215 /* Various things can be inserted at the start of a line. Don't use the
216 tod_stamp() function for the timestamp, because that will overwrite the
217 timestamp buffer, which may contain something useful. (This was a bug fix: the
218 +memory debugging with +timestamp did cause a problem.) */
220 if (debug_ptr == debug_buffer)
228 gettimeofday(&now, NULL);
230 t = f.timestamps_utc ? gmtime(&tmp) : localtime(&tmp);
231 debug_ptr += sprintf(CS debug_ptr,
232 LOGGING(millisec) ? "%02d:%02d:%02d.%03d " : "%02d:%02d:%02d ",
233 t->tm_hour, t->tm_min, t->tm_sec, (int)(now.tv_usec/1000));
237 debug_ptr += sprintf(CS debug_ptr, "%5d ", (int)getpid());
239 /* Set up prefix if outputting for host checking and not debugging */
241 if (host_checking && debug_selector == 0)
243 Ustrcpy(debug_ptr, US">>> ");
247 debug_prefix_length = debug_ptr - debug_buffer;
252 for (int i = indent >> 2; i > 0; i--)
255 Ustrcpy(debug_ptr, US" !");
256 debug_ptr += 4; /* 3 spaces + shriek */
257 debug_prefix_length += 4;
261 Ustrcpy(debug_ptr, US" " UTF8_VERT_2DASH);
262 debug_ptr += 6; /* 3 spaces + 3 UTF-8 octets */
263 debug_prefix_length += 6;
266 Ustrncpy(debug_ptr, US" ", indent &= 3);
268 debug_prefix_length += indent;
271 /* Use the lengthchecked formatting routine to ensure that the buffer
272 does not overflow. Ensure there's space for a newline at the end.
273 However, use taint-unchecked routines for writing into the buffer
274 so that we can write tainted info into the static debug_buffer -
275 we trust that we will never expand the results. */
278 gstring gs = { .size = (int)sizeof(debug_buffer) - 1,
279 .ptr = debug_ptr - debug_buffer,
281 if (!string_vformat(&gs, SVFMT_TAINT_NOCHK, format, ap))
283 uschar * s = US"**** debug string too long - truncated ****\n";
284 uschar * p = gs.s + gs.ptr;
285 int maxlen = gs.size - Ustrlen(s) - 2;
286 if (p > gs.s + maxlen) p = gs.s + maxlen;
287 if (p > gs.s && p[-1] != '\n') *p++ = '\n';
289 while(*debug_ptr) debug_ptr++;
293 string_from_gstring(&gs);
294 debug_ptr = gs.s + gs.ptr;
298 /* Output the line if it is complete. If we added any prefix data and there
299 are internal newlines, make sure the prefix is on the continuation lines,
300 as long as there is room in the buffer. We want to do just a single fprintf()
301 so as to avoid interleaving. */
303 if (debug_ptr[-1] == '\n')
305 if (debug_prefix_length > 0)
307 uschar *p = debug_buffer;
308 int left = sizeof(debug_buffer) - (debug_ptr - debug_buffer) - 1;
309 while ((p = Ustrchr(p, '\n') + 1) != debug_ptr &&
310 left >= debug_prefix_length)
312 int len = debug_ptr - p;
313 memmove(p + debug_prefix_length, p, len + 1);
314 memmove(p, debug_buffer, debug_prefix_length);
315 debug_ptr += debug_prefix_length;
316 left -= debug_prefix_length;
320 fprintf(debug_file, "%s", CS debug_buffer);
322 debug_ptr = debug_buffer;
323 debug_prefix_length = 0;
330 /* Output the details of a socket */
333 debug_print_socket(int fd)
336 if (fstat(fd, &s) == 0 && (s.st_mode & S_IFMT) == S_IFSOCK)
340 socklen_t vlen = sizeof(val);
341 struct sockaddr_storage a;
342 socklen_t alen = sizeof(a);
343 struct sockaddr_in * sinp = (struct sockaddr_in *)&a;
344 struct sockaddr_in6 * sin6p = (struct sockaddr_in6 *)&a;
345 struct sockaddr_un * sunp = (struct sockaddr_un *)&a;
347 if (getsockname(fd, (struct sockaddr*)&a, &alen) == 0)
351 g = string_cat(g, US"domain AF_INET");
352 g = string_fmt_append(g, " lcl [%s]:%u",
353 inet_ntoa(sinp->sin_addr), ntohs(sinp->sin_port));
354 alen = sizeof(*sinp);
355 if (getpeername(fd, (struct sockaddr *)sinp, &alen) == 0)
356 g = string_fmt_append(g, " rmt [%s]:%u",
357 inet_ntoa(sinp->sin_addr), ntohs(sinp->sin_port));
362 g = string_cat(g, US"domain AF_INET6");
363 g = string_fmt_append(g, " lcl [%s]:%u",
364 inet_ntop(AF_INET6, &sin6p->sin6_addr, CS buf, sizeof(buf)),
365 ntohs(sin6p->sin6_port));
366 alen = sizeof(*sin6p);
367 if (getpeername(fd, (struct sockaddr *)sin6p, &alen) == 0)
368 g = string_fmt_append(g, " rmt [%s]:%u",
369 inet_ntop(AF_INET6, &sin6p->sin6_addr, CS buf, sizeof(buf)),
370 ntohs(sin6p->sin6_port));
374 g = string_cat(g, US"domain AF_UNIX");
375 if (alen > sizeof(sa_family_t)) /* not unix(7) "unnamed socket" */
376 g = string_fmt_append(g, " lcl %s%s",
377 sunp->sun_path[0] ? US"" : US"@",
378 sunp->sun_path[0] ? sunp->sun_path : sunp->sun_path+1);
379 alen = sizeof(*sunp);
380 if (getpeername(fd, (struct sockaddr *)sunp, &alen) == 0)
381 g = string_fmt_append(g, " rmt %s%s",
382 sunp->sun_path[0] ? US"" : US"@",
383 sunp->sun_path[0] ? sunp->sun_path : sunp->sun_path+1);
386 g = string_fmt_append(g, "domain %u", sinp->sin_family);
389 if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &val, &vlen) == 0)
392 case SOCK_STREAM: g = string_cat(g, US" type SOCK_STREAM"); break;
393 case SOCK_DGRAM: g = string_cat(g, US" type SOCK_DGRAM"); break;
394 default: g = string_fmt_append(g, " type %d", val); break;
397 if (getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, &val, &vlen) == 0)
399 struct protoent * p = getprotobynumber(val);
401 ? string_fmt_append(g, " proto %s", p->p_name)
402 : string_fmt_append(g, " proto %d", val);
405 debug_printf_indent(" socket: %s\n", string_from_gstring(g));
408 debug_printf_indent(" fd st_mode 0%o\n", s.st_mode);